Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 13360782 | 213 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
HashLordzMiner
Compiler Version
v0.8.26+commit.8a97fa7a
ZkSolc Version
v1.5.15
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {EnumerableSetLib} from "solady/src/utils/EnumerableSetLib.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
import {IHashcoin} from "./interfaces/IHashcoin.sol";
import {Miner} from "./types/Miner.sol";
import {Facility} from "./types/Facility.sol";
import {NewFacility} from "./types/NewFacility.sol";
import {Errors} from "./libraries/Errors.sol";
import {Events} from "./libraries/Events.sol";
// import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
// Hashcoin main program
contract HashLordzMiner is Initializable, OwnableUpgradeable {
using EnumerableSetLib for EnumerableSetLib.Uint256Set;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// STORAGE
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/// @dev Hashcoin token address.
address public hashcoin;
/// @dev hashtoshi fee recipient.
address public hashtoshi;
address public lordztoshi;
address public printoshi;
/// @dev Mining start block.
uint256 public startBlock;
bool public miningHasStarted;
// every miner has an id
uint256 universalMinerId;
uint256 public initialMinerCnt;
/// @dev Total unique miners.
uint256 public uniqueMinerCount;
/// @dev Total facilities.
uint256 public facilityCount;
/// @dev Tracks last time we updated rewards.
uint256 public lastRewardBlock;
/// @dev Total network hashrate.
uint256 public totalHashrate;
/// @dev Tracks hashcoin per single hash.
uint256 public cumulativeHashcoinPerHash;
/// @dev Initial cooldown time is 24H.
uint256 public cooldown;
/// @dev Initial referral fee is 5.0%.
uint256 public referralFee;
/// @dev Initial burn is 75%.
uint256 public burnPct;
/// @dev Players total hashrate.
mapping(address => uint256) public playerHashrate;
/// @dev Players pending rewards.
mapping(address => uint256) public playerPendingRewards;
/// @dev Players debt (updated after rewards are updated for a player).
mapping(address => uint256) public playerHashcoinDebt;
/// @dev Tracks different miners and its stats.
mapping(uint256 => Miner) public miners;
/// @dev Tracks different facilities and its stats.
mapping(uint256 => NewFacility) public facilities;
/// @dev Tracks how many of each miner a player has. Only tracks Id.
mapping(address => EnumerableSetLib.Uint256Set) public playerMinersOwned;
/// @dev Maps minerId to the actual miner struct
mapping(uint256 => Miner) public playerMinersId;
/// @dev Tracks players facility stats.
mapping(address => Facility) public ownerToFacility;
/// @dev Tracks new players initializing in the game.
mapping(address => bool) public initializedStarterFacility;
/// @dev Tracks each miners coords for a player
mapping(address => mapping(uint256 => bool)) public playerOccupiedCoords;
mapping(address => uint256) public lastFacilityUpgradeTimestamp;
/// @dev Tracks referrals.
mapping(address => address) public referrals;
/// @dev Tracks referred users.
mapping(address => address[]) public referredUsers;
/// @dev Track how much each referrer got paid.
mapping(address => uint256) public referralBonusPaid;
/// @dev start miner and facility index (these will never change since every player starts with same facility).
uint256 public constant STARTER_MINER_INDEX = 1;
uint256 public constant STARTER_FACILITY_INDEX = 1;
/// @dev Halvening every 6,500,000 blocks, roughly 80 days
uint256 public HALVING_INTERVAL;
/// @dev Initial hashcoin per block
uint256 public INITIAL_HASHCOIN_PER_BLOCK;
uint256 public constant REWARDS_PRECISION = 1e18;
/// @dev NEW: maximum supply of hashcoin
uint256 public constant MAX_SUPPLY = 33_000_000e18;
/// @dev NEW: Excess issuance caused by delayed halving adjustment
uint public halvingOvershoot;
/// @dev NEW: ETH Price Feed
IPyth public pythNetwork;
uint public maxPythPriceAge;
bytes32 public pythPriceId;
/// @dev NEW: ETH-HASH Pool Info
address public wethAddress;
address public poolAddress;
bool public isTokenTradeable;
/// @dev NEW: Miners ID Listed on Marketplace
EnumerableSetLib.Uint256Set public minersListedOnMarketplace;
/// @dev Initial marketFee is 20%
uint256 public marketFee;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CONSTRUCTOR
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
function initialize() public initializer {
__Ownable_init(msg.sender);
/// @dev Initial cooldown time is 24H.
cooldown = 24 hours;
/// @dev Initial referral fee is 5.0%.
referralFee = 0.05e18;
/// @dev Initial burn is 75%.
burnPct = 0.75e18;
/// @dev Initial marketFee is 20%
marketFee = 20;
/// @dev Halvening every 6,500,000 blocks, roughly 80 days
HALVING_INTERVAL = 6_500_000;
/// @dev Initial hashcoin per block
INITIAL_HASHCOIN_PER_BLOCK = 0.5e18;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// USER FUNCTIONS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/**
* @dev All new players must purchase an initial facility with ETH.
*
* Players can only purchase new facilities after acquiring initial Facility.
*/
function purchaseInitialFacility(address referrer) external payable {
if (msg.value != getInitialFacilityPrice()) {
revert Errors.IncorrectValue();
}
if (initializedStarterFacility[msg.sender]) {
revert Errors.AlreadyPurchasedInitialFactory();
}
if (referrer == msg.sender) {
revert Errors.InvalidReferrer();
}
initializedStarterFacility[msg.sender] = true;
if (referrer != address(0)) {
referrals[msg.sender] = referrer;
referredUsers[referrer].push(msg.sender);
}
NewFacility memory newFacility = facilities[STARTER_FACILITY_INDEX];
Facility storage facility = ownerToFacility[msg.sender];
// initialize players starter facility
facility.facilityIndex = STARTER_FACILITY_INDEX;
facility.maxMiners = newFacility.maxMiners;
lastFacilityUpgradeTimestamp[msg.sender] = block.timestamp;
emit Events.InitialFacilityPurchased(msg.sender);
/// Add Free Miner ///
Miner memory miner = miners[STARTER_MINER_INDEX];
miner.x = 0;
miner.id = ++universalMinerId;
miner.owner = msg.sender;
playerOccupiedCoords[msg.sender][0] = true;
playerMinersOwned[msg.sender].add(universalMinerId);
playerMinersId[universalMinerId] = miner;
// increase facility miners
facility.currMiners++;
// increase initial Miner Count
initialMinerCnt++;
// emit Events.FreeMinerRedeemed(msg.sender);
emit Events.MinerBought(msg.sender, STARTER_MINER_INDEX, 0, universalMinerId, 0);
_increaseHashrate(msg.sender, miner.hashrate);
}
/**
* @dev All new players must purchase an initial facility with ETH.
*
* Players can only purchase new facilities after acquiring initial Facility.
*/
function purchaseInitialFacilityFree(address user) external onlyOwner {
if (initializedStarterFacility[user]) {
revert Errors.AlreadyPurchasedInitialFactory();
}
initializedStarterFacility[user] = true;
NewFacility memory newFacility = facilities[STARTER_FACILITY_INDEX];
Facility storage facility = ownerToFacility[user];
// initialize players starter facility
facility.facilityIndex = STARTER_FACILITY_INDEX;
facility.maxMiners = newFacility.maxMiners;
lastFacilityUpgradeTimestamp[user] = block.timestamp;
emit Events.InitialFacilityPurchased(user);
/// Add Free Miner ///
Miner memory miner = miners[STARTER_MINER_INDEX];
miner.x = 0;
miner.id = ++universalMinerId;
miner.owner = user;
playerOccupiedCoords[user][0] = true;
playerMinersOwned[user].add(universalMinerId);
playerMinersId[universalMinerId] = miner;
// increase facility miners
facility.currMiners++;
// increase initial Miner Count
initialMinerCnt++;
emit Events.MinerBought(user, STARTER_MINER_INDEX, 0, universalMinerId, 0);
_increaseHashrate(user, miner.hashrate);
}
/**
* @dev Purchase new miners using hashcoin.
*/
function buyMiner(uint256 minerIndex) external {
// check user has enough funds for miner and facility allows it
Miner memory miner = miners[minerIndex];
Facility storage facility = ownerToFacility[msg.sender];
if (minerIndex > facility.facilityIndex) {
revert Errors.InvalidMinerIndex();
}
// this case will cover if an index too large is passed in
if (!miner.inProduction) revert Errors.MinerNotInProduction();
if (!isTokenTradeable) revert Errors.TokenNotTradeable();
uint256 tokenAmt = getTokenAmountFromEthAmount(miner.cost);
if (IHashcoin(hashcoin).balanceOf(msg.sender) < tokenAmt) {
revert Errors.TooPoor();
}
// transfer correct amt of hashcoin
IHashcoin(hashcoin).transferFrom(msg.sender, address(this), tokenAmt);
// burn
IHashcoin(hashcoin).burn(FixedPointMathLib.mulWad(tokenAmt, burnPct));
miner.x = 100;
miner.id = ++universalMinerId;
miner.owner = msg.sender;
playerMinersOwned[msg.sender].add(universalMinerId);
playerMinersId[universalMinerId] = miner;
emit Events.MinerBought(msg.sender, minerIndex, tokenAmt, universalMinerId, 100);
}
/**
* @dev Start Mining
*/
function startMining(uint256 minerId, uint256 x) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
Miner storage miner = playerMinersId[minerId];
Facility storage facility = ownerToFacility[msg.sender];
if (_isInvalidCoordinates(x, facility.maxMiners)) {
revert Errors.InvalidMinerCoordinates();
}
// this case will cover if an index too large is passed in
if (!miner.inProduction) revert Errors.MinerNotInProduction();
// this case will cover if miner is already mining
if (miner.x != 100) revert Errors.MinerInMining();
// this case will cover if miner is in marketplace
if (miner.isListedSell) revert Errors.MinerInMarket();
miner.x = x;
playerOccupiedCoords[msg.sender][x] = true;
// increase facility miners
facility.currMiners++;
emit Events.StartedMining(msg.sender, minerId, x);
_increaseHashrate(msg.sender, miner.hashrate * miner.level);
}
/**
* @dev Stop Mining
*/
function stopMining(uint256 minerId) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
Miner storage miner = playerMinersId[minerId];
Facility storage facility = ownerToFacility[msg.sender];
// this case will cover if an index too large is passed in
if (!miner.inProduction) revert Errors.MinerNotInProduction();
// this case will cover if miner is already in store
if (miner.x == 100) revert Errors.MinerInStore();
// this case will cover if miner is in marketplace
if (miner.isListedSell) revert Errors.MinerInMarket();
playerOccupiedCoords[msg.sender][miner.x] = false;
miner.x = 100;
// increase facility miners
facility.currMiners--;
emit Events.StoppedMining(msg.sender, minerId);
_decreaseHashrate(msg.sender, miner.hashrate * miner.level);
}
/**
* @dev Update miner stats.
*
* This function is called when a miner is updated, e.g., after a certain time period or event.
* It checks if the player owns the miner and updates its coordinates and production status.
*/
function updateMiner(uint256 minerId) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
Miner storage miner = playerMinersId[minerId];
// update miner in production status
if (!miner.inProduction) {
revert Errors.MinerNotInProduction();
}
miner.level ++;
if (miner.level > 5) {
revert Errors.MinerFullUpdated();
}
if (!isTokenTradeable) revert Errors.TokenNotTradeable();
uint256 tokenAmt = getTokenAmountFromEthAmount(miner.cost);
if (IHashcoin(hashcoin).balanceOf(msg.sender) < tokenAmt) {
revert Errors.TooPoor();
}
// transfer correct amt of hashcoin
IHashcoin(hashcoin).transferFrom(msg.sender, address(this), tokenAmt);
// burn
IHashcoin(hashcoin).burn(FixedPointMathLib.mulWad(tokenAmt, burnPct));
emit Events.MinerUpdated(msg.sender, miner.minerIndex, miner.level, minerId, miner.x);
if (miner.x != 100)
_increaseHashrate(msg.sender, miner.hashrate);
}
/**
* @dev Remove miners, if there's a secondary market, player will get hashcoin in return.
*
* Players will remove miners in the case they run out of spots in their facility to put new miners.
*/
function removeMiner(uint256 minerId) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
Miner memory miner = playerMinersId[minerId];
if (miner.x != 100) revert Errors.MinerInMining();
playerMinersOwned[msg.sender].remove(minerId);
delete playerMinersId[minerId];
playerOccupiedCoords[msg.sender][miner.x] = false;
emit Events.MinerSold(msg.sender, miner.minerIndex, 0, minerId, miner.x);
}
function listForSale(uint256 minerId, uint256 price) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
Miner storage miner = playerMinersId[minerId];
// this case will cover if an index too large is passed in
if (!miner.inProduction) revert Errors.MinerNotInProduction();
// this case will cover if miner is already in store
if (miner.isListedSell) revert Errors.MinerInMarket();
miner.isListedSell = true;
miner.sellPrice = price;
minersListedOnMarketplace.add(minerId);
emit Events.ListedForSale(msg.sender, minerId);
}
function cancelListForSale(uint256 minerId) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
if (!minersListedOnMarketplace.contains(minerId)) {
revert Errors.NotListedMinerOnMarketplace();
}
Miner storage miner = playerMinersId[minerId];
// this case will cover if an index too large is passed in
if (!miner.inProduction) revert Errors.MinerNotInProduction();
// this case will cover if miner is already in store
if (!miner.isListedSell) revert Errors.MinerInStore();
miner.isListedSell = false;
miner.sellPrice = 0;
minersListedOnMarketplace.remove(minerId);
emit Events.ListedForSale(msg.sender, minerId);
}
function buyMinerFromMarket(uint256 minerId) external payable {
if (!minersListedOnMarketplace.contains(minerId)) {
revert Errors.NotListedMinerOnMarketplace();
}
Miner storage miner = playerMinersId[minerId];
if (msg.value != miner.sellPrice) {
revert Errors.IncorrectValue();
}
(bool success,) = payable(miner.owner).call{value: miner.sellPrice * (100 - marketFee) / 100}("");
if (!success) revert Errors.WithdrawFailed();
playerMinersOwned[miner.owner].remove(minerId);
playerMinersOwned[msg.sender].add(minerId);
minersListedOnMarketplace.remove(minerId);
emit Events.MinerBoughtOnMarketplace(miner.owner, msg.sender, miner.minerIndex, universalMinerId, miner.sellPrice);
miner.isListedSell = false;
miner.sellPrice = 0;
miner.x = 100;
miner.owner = msg.sender;
}
/**
* @dev Purchase larger or more power output facility.
*
* Players must linearly climb the facilities.
*/
function buyNewFacility() external {
// need to purchase initial facility first
if (!initializedStarterFacility[msg.sender]) {
revert Errors.NeedToInitializeFacility();
}
Facility storage currFacility = ownerToFacility[msg.sender];
uint256 currFacilityIndex = currFacility.facilityIndex;
if (currFacilityIndex == facilityCount) {
revert Errors.AlreadyAtMaxFacility();
}
// 24H cooldown between each facility upgrade
if (block.timestamp - lastFacilityUpgradeTimestamp[msg.sender] < cooldown) {
revert Errors.CantBuyNewFacilityYet();
}
NewFacility memory newFacility = facilities[currFacilityIndex + 1];
if (!newFacility.inProduction) {
revert Errors.NewFacilityNotInProduction();
}
if (!isTokenTradeable) revert Errors.TokenNotTradeable();
uint256 tokenAmt = getTokenAmountFromEthAmount(newFacility.cost);
if (IHashcoin(hashcoin).balanceOf(msg.sender) < tokenAmt) {
revert Errors.TooPoor();
}
IHashcoin(hashcoin).transferFrom(msg.sender, address(this), tokenAmt);
// burn
IHashcoin(hashcoin).burn(FixedPointMathLib.mulWad(tokenAmt, burnPct));
currFacility.facilityIndex++;
currFacility.maxMiners = newFacility.maxMiners;
lastFacilityUpgradeTimestamp[msg.sender] = block.timestamp;
emit Events.FacilityBought(msg.sender, currFacility.facilityIndex, tokenAmt);
}
/**
* @dev Claim rewards for player.
*/
function claimRewards() external {
_updateRewards(msg.sender);
uint256 rewards = playerPendingRewards[msg.sender];
if (rewards == 0) {
revert Errors.NoRewardsPending();
}
playerPendingRewards[msg.sender] = 0;
// referral bonus
uint256 referralBonus = FixedPointMathLib.mulWad(rewards, referralFee);
uint256 finalRewards = rewards - referralBonus;
_mint(msg.sender, finalRewards);
address referrer = referrals[msg.sender];
if (referrer != address(0)) {
_mint(referrer, referralBonus);
referralBonusPaid[referrer] += referralBonus;
} else {
// else mint referral fee to this contract
_mint(address(this), referralBonus);
referralBonusPaid[address(this)] += referralBonus;
}
emit Events.RewardsClaimed(msg.sender, rewards);
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// INTERNAL FUNCTIONS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/**
* @dev Update global cumulative rewards before game state changes.
*/
function _updateCumulativeRewards() internal {
if (totalHashrate == 0) {
lastRewardBlock = block.number;
return;
}
// if we have not updated rewards and a halvening occurs, we must add the different
// hashcoin emissions per halvening
uint256 currentBlock = lastRewardBlock;
uint256 lastHashcoinPerBlock =
INITIAL_HASHCOIN_PER_BLOCK / (2 ** ((lastRewardBlock - startBlock) / HALVING_INTERVAL));
while (currentBlock < block.number) {
uint256 nextHalvingBlock =
startBlock + (((currentBlock - startBlock) / HALVING_INTERVAL) + 1) * HALVING_INTERVAL;
uint256 endBlock = (nextHalvingBlock < block.number) ? nextHalvingBlock : block.number;
// apply correct emission rate for this segment
cumulativeHashcoinPerHash +=
((lastHashcoinPerBlock * (endBlock - currentBlock) * REWARDS_PRECISION) / totalHashrate);
// move to next segment
currentBlock = endBlock;
// if a halving has happened, apply the new rate
if (currentBlock == nextHalvingBlock) {
lastHashcoinPerBlock /= 2;
}
}
lastRewardBlock = block.number;
}
function _updateRewards(address player) internal {
_updateCumulativeRewards();
playerPendingRewards[player] +=
(playerHashrate[player] * (cumulativeHashcoinPerHash - playerHashcoinDebt[player])) / REWARDS_PRECISION;
playerHashcoinDebt[player] = cumulativeHashcoinPerHash;
}
/**
* @dev Increase players hashrate.
*/
function _increaseHashrate(address player, uint256 hashrate) internal {
// only start rewarding hashcoin per block when the first miner is added
if (!miningHasStarted) {
miningHasStarted = true;
startBlock = block.number;
lastRewardBlock = block.number;
emit Events.MiningStarted(startBlock);
}
// update rewards and global state before modifying players state
_updateRewards(player);
totalHashrate += hashrate;
playerHashrate[player] += hashrate;
emit Events.PlayerHashrateIncreased(msg.sender, playerHashrate[player], playerPendingRewards[player]);
}
/**
* @dev Decrease players hashrate.
*/
function _decreaseHashrate(address player, uint256 hashrate) internal {
// update rewards and global state before modifying players state
_updateRewards(player);
totalHashrate -= hashrate;
playerHashrate[player] -= hashrate;
emit Events.PlayerHashrateDecreased(msg.sender, playerHashrate[player], playerPendingRewards[player]);
}
/**
* @dev checks the miners x coords are within bounds and there isn't an existent miner at that position.
*/
function _isInvalidCoordinates(uint256 desiredX, uint256 facilityX)
internal
view
returns (bool)
{
if (desiredX >= facilityX) {
return true;
}
return playerOccupiedCoords[msg.sender][desiredX];
}
/**
* @dev Minting is performed only after verifying that the sum of the total supply, the amount burned, and the mint amount does not exceed 21 million.
*/
function _mint(address to, uint amount) internal {
uint256 amtBurned = IHashcoin(hashcoin).amtBurned();
uint256 supply = IHashcoin(hashcoin).totalSupply();
require(amtBurned + supply + amount <= MAX_SUPPLY + halvingOvershoot, "The sum of the total supply, the amount burned, and the mint amount must not exceed the max supply");
IHashcoin(hashcoin).mint(to, amount);
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// VIEW FUNCTIONS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/**
* @dev Get the current mining emission rate based on halvings
*/
function getHashcoinPerBlock() public view returns (uint256) {
if (!miningHasStarted) {
return 0;
}
uint256 halvingsSinceStart = (block.number - startBlock) / HALVING_INTERVAL;
return INITIAL_HASHCOIN_PER_BLOCK / (2 ** halvingsSinceStart);
}
/**
* @dev Get current pending rewards for player.
*/
function pendingRewards(address player) external view returns (uint256) {
// below is basically the same logic as _updateCumulativeRewards() but doesnt change state
if (!miningHasStarted) {
return 0;
}
if (totalHashrate == 0) {
return FixedPointMathLib.mulWad(playerPendingRewards[player], 1e18 - referralFee);
}
uint256 currentBlock = lastRewardBlock;
uint256 lastHashcoinPerBlock =
INITIAL_HASHCOIN_PER_BLOCK / (2 ** ((lastRewardBlock - startBlock) / HALVING_INTERVAL));
uint256 simulatedCumulativeHashcoinPerHash = cumulativeHashcoinPerHash;
while (currentBlock < block.number) {
uint256 nextHalvingBlock =
startBlock + (((currentBlock - startBlock) / HALVING_INTERVAL) + 1) * HALVING_INTERVAL;
uint256 endBlock = (nextHalvingBlock < block.number) ? nextHalvingBlock : block.number;
// simulate rewards accumulation
if (totalHashrate > 0) {
simulatedCumulativeHashcoinPerHash +=
((lastHashcoinPerBlock * (endBlock - currentBlock) * REWARDS_PRECISION) / totalHashrate);
}
// move to next segment
currentBlock = endBlock;
// if we reached a halving point, apply the new emission rate
if (currentBlock == nextHalvingBlock) {
lastHashcoinPerBlock /= 2;
}
}
return FixedPointMathLib.mulWad(
playerPendingRewards[player]
+ (
(playerHashrate[player] * (simulatedCumulativeHashcoinPerHash - playerHashcoinDebt[player]))
/ REWARDS_PRECISION
),
1e18 - referralFee
);
}
/**
* @dev Get current hashcoin a player mines per block.
*/
function playerHashcoinPerBlock(address player) external view returns (uint256) {
if (totalHashrate == 0) {
return 0; // Prevent division by zero
}
uint256 currHashcoinPerBlock =
INITIAL_HASHCOIN_PER_BLOCK / (2 ** ((block.number - startBlock) / HALVING_INTERVAL));
return FixedPointMathLib.mulDiv(playerHashrate[player], currHashcoinPerBlock, totalHashrate);
}
/**
* @dev Get blocks till next halvening.
*/
function blocksUntilNextHalving() external view returns (uint256) {
if (startBlock == 0) revert Errors.MiningHasntStarted();
uint256 nextHalvingBlock =
startBlock + (((block.number - startBlock) / HALVING_INTERVAL) + 1) * HALVING_INTERVAL;
return nextHalvingBlock - block.number;
}
/**
* @dev Get next available facility upgrade time.
*/
function timeUntilNextFacilityUpgrade(address player) external view returns (uint256) {
if (lastFacilityUpgradeTimestamp[player] + cooldown < block.timestamp) {
return 0;
}
return (lastFacilityUpgradeTimestamp[player] + cooldown) - block.timestamp;
}
/**
* @dev Get all miners for a player.
*/
function getPlayerMinersPaginated(address player, uint256 startIndex, uint256 size)
external
view
returns (Miner[] memory)
{
EnumerableSetLib.Uint256Set storage set = playerMinersOwned[player];
uint256 length = set.length();
// Return empty array if start index is beyond array bounds
if (startIndex >= length) {
return new Miner[](0);
}
// Calculate how many items we can actually return
uint256 remaining = length - startIndex;
uint256 returnSize = size > remaining ? remaining : size;
Miner[] memory playerMiners = new Miner[](returnSize);
for (uint256 i = 0; i < returnSize; i++) {
playerMiners[i] = playerMinersId[set.at(startIndex + i)];
}
return playerMiners;
}
/**
* @dev Get all miners on marketplace.
*/
function getMinersOnMarketplace()
external
view
returns (Miner[] memory)
{
uint256 length = minersListedOnMarketplace.length();
Miner[] memory playerMiners = new Miner[](length);
for (uint256 i = 0; i < length; i++) {
playerMiners[i] = playerMinersId[minersListedOnMarketplace.at(i)];
}
return playerMiners;
}
/**
* @dev Get all referred users.
*/
function getReferrals(address referrer) external view returns (address[] memory) {
return referredUsers[referrer];
}
/**
* @dev Get Initial Facility Price based on initialMinerCnt.
*/
function getInitialFacilityPrice() public view returns (uint256 price) {
if (initialMinerCnt < 250)
return 0.01 ether;
else if (initialMinerCnt >= 250 && initialMinerCnt < 750)
return 0.015 ether;
else if (initialMinerCnt >= 750)
return 0.02 ether;
}
/**
* @dev Get Next Initial Facility Price based on initialMinerCnt.
*/
function getNextInitialFacilityPrice() external view returns (uint256 price) {
if (initialMinerCnt < 250)
return 0.015 ether;
else if (initialMinerCnt >= 250 && initialMinerCnt < 750)
return 0.02 ether;
else if (initialMinerCnt >= 750)
return 0.02 ether;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// OWNER FUNCTIONS
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/**
* @dev Add new miner to game.
*/
function addMiner(uint256 hashrate, uint256 cost, bool inProduction) external onlyOwner {
// must increment first cause compiler evaluates function arg before evaluating the assignment
++uniqueMinerCount;
miners[uniqueMinerCount] = Miner(uniqueMinerCount, 0, 0, hashrate, 1, cost, false, 0, 0x0000000000000000000000000000000000000000, inProduction);
emit Events.NewMinerAdded(uniqueMinerCount, hashrate, cost, inProduction);
}
/**
* @dev Allows or prevents miner from being purchased.
*
* Miners cannot be removed, only toggled off from purchased.
*/
function toggleMinerProduction(uint256 minerIndex, bool inProduction) external onlyOwner {
if (minerIndex < STARTER_MINER_INDEX || minerIndex > uniqueMinerCount) {
revert Errors.InvalidMinerIndex();
}
Miner storage miner = miners[minerIndex];
miner.inProduction = inProduction;
emit Events.MinerProductionToggled(minerIndex, inProduction);
}
/**
* @dev Add new facility to game.
*/
function addFacility(
uint256 maxMiners,
uint256 cost,
bool inProduction
) external onlyOwner {
++facilityCount;
facilities[facilityCount] = NewFacility(maxMiners, cost, inProduction);
emit Events.NewFacilityAdded(facilityCount, cost, inProduction);
}
/**
* @dev Allows or prevents new facilities from being purchased.
*
* New facilities cannot be removed, only toggled off from purchased.
*/
function toggleFacilityProduction(uint256 facilityIndex, bool inProduction) external onlyOwner {
if (facilityIndex < STARTER_FACILITY_INDEX || facilityIndex > facilityCount) {
revert Errors.InvalidFacilityIndex();
}
NewFacility storage facility = facilities[facilityIndex];
facility.inProduction = inProduction;
emit Events.FacilityProductionToggled(facilityIndex, inProduction);
}
function setHashcoin(address _hashcoin) external onlyOwner {
hashcoin = _hashcoin;
}
function setHashtoshi(address _hashtoshi) external onlyOwner {
hashtoshi = _hashtoshi;
}
function setLordztoshi(address _lordztoshi) external onlyOwner {
lordztoshi = _lordztoshi;
}
function setPrintoshi(address _printoshi) external onlyOwner {
printoshi = _printoshi;
}
function setReferralFee(uint256 fee) external onlyOwner {
if (fee > 1e18) revert Errors.InvalidFee();
referralFee = fee;
}
function setBurnPct(uint256 burn) external onlyOwner {
if (burn > 1e18) revert Errors.InvalidFee();
burnPct = burn;
}
function setCooldown(uint256 _cooldown) external onlyOwner {
cooldown = _cooldown;
}
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
(bool success1,) = payable(hashtoshi).call{value: balance * 4 / 10}("");
(bool success2,) = payable(lordztoshi).call{value: balance * 4 / 10}("");
(bool success3,) = payable(printoshi).call{value: balance *2 / 10}("");
if (!success1 || !success2 || !success3) revert Errors.WithdrawFailed();
}
function withdrawHashcoin(uint256 amt) external onlyOwner {
IHashcoin(hashcoin).transfer(hashtoshi, amt * 4 / 10);
IHashcoin(hashcoin).transfer(lordztoshi, amt * 4 / 10);
IHashcoin(hashcoin).transfer(printoshi, amt * 2 / 10);
}
function changeMinerCost(uint256 minerIndex, uint256 newCost) external onlyOwner {
if (minerIndex > uniqueMinerCount) {
revert Errors.NonExistentMiner();
}
if (minerIndex == STARTER_MINER_INDEX) {
revert Errors.CantModifyStarterMiner();
}
Miner storage miner = miners[minerIndex];
miner.cost = newCost;
emit Events.MinerCostChanged(minerIndex, newCost);
}
function changeFacilityCost(uint256 facilityIndex, uint256 newCost) external onlyOwner {
if (facilityIndex > facilityCount) {
revert Errors.NonExistentFacility();
}
if (facilityIndex == STARTER_FACILITY_INDEX) {
revert Errors.CantModifyStarterFacility();
}
NewFacility storage facility = facilities[facilityIndex];
facility.cost = newCost;
emit Events.FacilityCostChanged(facilityIndex, newCost);
}
/**
* @dev Get ETH price from Pyth Network.
*/
function getEthPrice() public view returns (uint256) {
PythStructs.Price memory priceDataByPyth = pythNetwork.getPriceNoOlderThan(pythPriceId, maxPythPriceAge);
require(priceDataByPyth.price > 0, "Invalid price");
return uint256(uint64(priceDataByPyth.price));
}
function setPyth(address _pythAddress, uint _maxPythPriceAge, bytes32 _priceId) external onlyOwner {
pythNetwork = IPyth(_pythAddress);
maxPythPriceAge = _maxPythPriceAge;
pythPriceId = _priceId;
}
/**
* @dev Get token amount from ETH amount.
* This function is a placeholder and should be implemented to convert ETH to token amount based on the current price.
*/
function getTokenAmountFromEthAmount(uint256 _ethAmount) public view returns (uint256) {
uint256 ethPrice = getEthPrice();
uint256 tokenAmount = IHashcoin(hashcoin).balanceOf(poolAddress);
uint8 tokenDecimal = IHashcoin(hashcoin).decimals();
uint256 wethAmount = IHashcoin(wethAddress).balanceOf(poolAddress);
uint8 wethDecimal = IHashcoin(wethAddress).decimals();
uint256 price = wethAmount * ethPrice / tokenAmount;
return _ethAmount * 1e18 / price;
}
function setPoolInfo(address _weth, address _pool, bool _isTokenTradeable) external onlyOwner {
wethAddress = _weth;
poolAddress = _pool;
isTokenTradeable = _isTokenTradeable;
}
function setHalvingInterval(uint256 _halvingInterval) external onlyOwner {
HALVING_INTERVAL = _halvingInterval;
}
function setInitialHashcoinPerBlock(uint256 _initialHashcoinPerBlock) external onlyOwner {
INITIAL_HASHCOIN_PER_BLOCK = _initialHashcoinPerBlock;
}
function setMarketFee(uint256 _marketFee) external onlyOwner {
marketFee = _marketFee;
}
}//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.19;
interface IHashcoin {
function minter() external view returns (address);
function mint(address to, uint256 amt) external;
function burn(uint256 value) external;
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function amtBurned() external returns (uint256);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @dev Miners that can be purchased in the game.
*/
struct Miner {
uint256 minerIndex;
uint256 id;
uint256 x;
uint256 hashrate;
uint256 level;
uint256 cost;
bool isListedSell;
uint256 sellPrice;
address owner;
bool inProduction;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library Events {
event MiningStarted(uint256 startBlock);
event NewMinerAdded(
uint256 indexed minerIndex, uint256 hashRate, uint256 cost, bool inProduction
);
event MinerProductionToggled(uint256 indexed minerIndex, bool inProduction);
event FacilityProductionToggled(uint256 indexed facilityIndex, bool inProduction);
event NewFacilityAdded(
uint256 indexed facilityIndex, uint256 cost, bool inProduction
);
event MinerSecondaryMarketAdded(uint256 indexed minerIndex, uint256 price);
event FreeFacilityPurchased(address indexed player);
event InitialFacilityPurchased(address indexed player);
event FreeMinerRedeemed(address indexed player);
event MinerSold(
address indexed player,
uint256 indexed minerIndex,
uint256 secondHandPrice,
uint256 minerId,
uint256 x
);
event MinerBought(
address indexed player, uint256 indexed minerIndex, uint256 cost, uint256 minerId, uint256 x
);
event MinerUpdated(
address indexed player, uint256 indexed minerIndex, uint256 level, uint256 minerId, uint256 x
);
event StartedMining(
address indexed player, uint256 indexed minerId, uint256 x
);
event StoppedMining(
address indexed player, uint256 indexed minerId
);
event ListedForSale(
address indexed player, uint256 indexed minerId
);
event FacilityBought(address indexed player, uint256 indexed facilityIndex, uint256 cost);
event PlayerHashrateIncreased(address indexed player, uint256 playerHashrate, uint256 playerPendingRewards);
event PlayerHashrateDecreased(address indexed player, uint256 playerHashrate, uint256 playerPendingRewards);
event RewardsClaimed(address indexed player, uint256 rewards);
event MinerCostChanged(uint256 indexed minerIndex, uint256 newCost);
event FacilityCostChanged(uint256 indexed facilityIndex, uint256 newCost);
// @dev NEW: Global Migration event
event Migration();
// @dev NEW: Player-realted Migration event
event PlayerHasMigrated(address player);
//
event MinerBoughtOnMarketplace(
address indexed oldOwner, address indexed newOwner, uint256 indexed minerIndex, uint256 minerId, uint256 cost
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @dev Current player's facility.
*/
struct Facility {
uint256 facilityIndex;
uint256 maxMiners;
uint256 currMiners;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
library Errors {
error IncorrectValue();
error AlreadyPurchasedFreeFactory();
error AlreadyPurchasedInitialFactory();
error StarterMinerAlreadyAcquired();
error FacilityAtMaxCapacity();
error PlayerDoesNotOwnMiner();
error MinerNotInProduction();
error MinerInStore();
error MinerInMining();
error MinerInMarket();
error TooPoor();
error NewFacilityNotInProduction();
error CannotDowngradeAFacility();
error NoRewardsPending();
error CannotDecreaseBelowZero();
error InvalidMinerCoordinates();
error FacilityDimensionsInvalid();
error NeedToInitializeFacility();
error InvalidReferrer();
error NonExistentMiner();
error CantModifyStarterMiner();
error NonExistentFacility();
error CantModifyStarterFacility();
error AlreadyAtMaxFacility();
error CantBuyNewFacilityYet();
error InvalidMinerIndex();
error InvalidFacilityIndex();
error InvalidFee();
error MiningHasntStarted();
error WithdrawFailed();
error MinerFullUpdated();
error NotListedMinerOnMarketplace();
error TokenNotTradeable();
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @dev Facilities that can be purchased in game.
*/
struct NewFacility {
uint256 maxMiners;
uint256 cost;
bool inProduction;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./PythStructs.sol";
import "./IPythEvents.sol";
/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how to consume prices safely.
/// @author Pyth Data Association
interface IPyth is IPythEvents {
/// @notice Returns the price of a price feed without any sanity checks.
/// @dev This function returns the most recent price update in this contract without any recency checks.
/// This function is unsafe as the returned price update may be arbitrarily far in the past.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use `getPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the price that is no older than `age` seconds of the current time.
/// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
/// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
/// However, if the price is not recent this function returns the latest available price.
///
/// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
/// the returned price is recent or useful for any particular application.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
/// of the current time.
/// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);
/// @notice Update price feeds with given update messages.
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
/// Prices will be updated if they are more recent than the current stored prices.
/// The call will succeed even if the update is not the most recent.
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
function updatePriceFeeds(bytes[] calldata updateData) external payable;
/// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is
/// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the
/// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
/// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime
/// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have
/// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.
/// Otherwise, it calls updatePriceFeeds method to update the prices.
///
/// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable;
/// @notice Returns the required fee to update an array of price updates.
/// @param updateData Array of price update data.
/// @return feeAmount The required fee in Wei.
function getUpdateFee(
bytes[] calldata updateData
) external view returns (uint feeAmount);
/// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
/// within `minPublishTime` and `maxPublishTime`.
///
/// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;
/// otherwise, please consider using `updatePriceFeeds`. This method may store the price updates on-chain, if they
/// are more recent than the current stored prices.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
///
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
/// no update for any of the given `priceIds` within the given time range.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdates(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
/// @notice Parse time-weighted average price (TWAP) from two consecutive price updates for the given `priceIds`.
///
/// This method calculates TWAP between two data points by processing the difference in cumulative price values
/// divided by the time period. It requires exactly two updates that contain valid price information
/// for all the requested price IDs.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the updateData array.
///
/// @dev Reverts if:
/// - The transferred fee is not sufficient
/// - The updateData is invalid or malformed
/// - The updateData array does not contain exactly 2 updates
/// - There is no update for any of the given `priceIds`
/// - The time ordering between data points is invalid (start time must be before end time)
/// @param updateData Array containing exactly two price updates (start and end points for TWAP calculation)
/// @param priceIds Array of price ids to calculate TWAP for
/// @return twapPriceFeeds Array of TWAP price feeds corresponding to the given `priceIds` (with the same order)
function parseTwapPriceFeedUpdates(
bytes[] calldata updateData,
bytes32[] calldata priceIds
)
external
payable
returns (PythStructs.TwapPriceFeed[] memory twapPriceFeeds);
/// @notice Similar to `parsePriceFeedUpdates` but ensures the updates returned are
/// the first updates published in minPublishTime. That is, if there are multiple updates for a given timestamp,
/// this method will return the first update. This method may store the price updates on-chain, if they
/// are more recent than the current stored prices.
///
///
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
/// no update for any of the given `priceIds` within the given time range and uniqueness condition.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdatesUnique(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
/// @dev Same as `parsePriceFeedUpdates`, but also returns the Pythnet slot
/// associated with each price update.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
/// @return slots Array of the Pythnet slot corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdatesWithSlots(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
)
external
payable
returns (
PythStructs.PriceFeed[] memory priceFeeds,
uint64[] memory slots
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if gt(x, div(not(0), y)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if iszero(eq(div(z, y), x)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := add(iszero(iszero(mod(z, WAD))), div(z, WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(mul(y, eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
/// Note: This function is an approximation.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
/// Note: This function is an approximation. Monotonically increasing.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
(int256 wad, int256 p) = (int256(WAD), x);
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (uint256(w >> 63) == uint256(0)) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == uint256(0)) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != uint256(0));
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c == uint256(0)) return w;
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a * b == x * y`, with full precision.
function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0))))
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`.
for {} 1 {} {
// If overflows.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
let r := mulmod(x, y, d) // Compute remainder using mulmod.
let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
// Make sure `z` is less than `2**256`. Also prevents `d == 0`.
// Placing the check here seems to give more optimal stack operations.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
d := div(d, t) // Divide `d` by `t`, which is a power of two.
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
z :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
)
break
}
z := div(z, d)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
/// Performs the full 512 bit calculation regardless.
function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z)))
let t := and(d, sub(0, d))
let r := mulmod(x, y, d)
d := div(d, t)
let inv := xor(2, mul(3, d))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
z :=
mul(
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv)
)
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
z = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
z := add(z, 1)
if iszero(z) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Calculates `floor(x * y / 2 ** n)` with full precision.
/// Throws if result overflows a uint256.
/// Credit to Philogy under MIT license:
/// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol
function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`.
for {} 1 {} {
if iszero(or(iszero(x), eq(div(z, x), y))) {
let k := and(n, 0xff) // `n`, cleaned.
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
// | p1 | z |
// Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 |
// Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 |
// Check that final `z` doesn't overflow by checking that p1_0 = 0.
if iszero(shr(k, p1)) {
z := add(shl(sub(256, k), p1), shr(k, z))
break
}
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
z := shr(and(n, 0xff), z)
break
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(z, d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(z, d))), div(z, d))
}
}
/// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`.
function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) {
/// @solidity memory-safe-assembly
assembly {
let g := n
let r := mod(a, n)
for { let y := 1 } 1 {} {
let q := div(g, r)
let t := g
g := r
r := sub(t, mul(r, q))
let u := x
x := y
y := sub(u, mul(y, q))
if iszero(r) { break }
}
x := mul(eq(g, 1), add(x, mul(slt(x, 0), n)))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `max(0, x - y)`.
function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `min(2 ** 256 - 1, x + y)`.
function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(sub(0, lt(add(x, y), x)), add(x, y))
}
}
/// @dev Returns `min(2 ** 256 - 1, x * y)`.
function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, address x, address y) internal pure returns (address z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Returns `x != 0 ? x : y`, without branching.
function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(x)))
}
}
/// @dev Returns `x != bytes32(0) ? x : y`, without branching.
function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(x)))
}
}
/// @dev Returns `x != address(0) ? x : y`, without branching.
function coalesce(address x, address y) internal pure returns (address z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, mul(y, iszero(shl(96, x))))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if x {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`, rounded down.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`, rounded down.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/snekmate/utils/math.vy
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// Makeshift lookup table to nudge the approximate log2 result.
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
// Newton-Raphson's.
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
// Round down.
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
z = (1 + sqrt(x)) * 10 ** 9;
z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
}
/// @solidity memory-safe-assembly
assembly {
z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down.
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
z = (1 + cbrt(x)) * 10 ** 12;
z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
}
/// @solidity memory-safe-assembly
assembly {
let p := x
for {} 1 {} {
if iszero(shr(229, p)) {
if iszero(shr(199, p)) {
p := mul(p, 100000000000000000) // 10 ** 17.
break
}
p := mul(p, 100000000) // 10 ** 8.
break
}
if iszero(shr(249, p)) { p := mul(p, 100) }
break
}
let t := mulmod(mul(z, z), z, p)
z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down.
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := 1
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for {} x { x := sub(x, 1) } { z := mul(z, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards zero.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
unchecked {
z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255);
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
internal
pure
returns (uint256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
unchecked {
if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
return a - fullMulDiv(a - b, t - begin, end - begin);
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
internal
pure
returns (int256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
// forgefmt: disable-next-item
unchecked {
if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a),
uint256(t - begin), uint256(end - begin)));
return int256(uint256(a) - fullMulDiv(uint256(a - b),
uint256(t - begin), uint256(end - begin)));
}
}
/// @dev Returns if `x` is an even number. Some people may need this.
function isEven(uint256 x) internal pure returns (bool) {
return x & uint256(1) == uint256(0);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for managing enumerable sets in storage.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EnumerableSetLib.sol)
///
/// @dev Note:
/// In many applications, the number of elements in an enumerable set is small.
/// This enumerable set implementation avoids storing the length and indices
/// for up to 3 elements. Once the length exceeds 3 for the first time, the length
/// and indices will be initialized. The amortized cost of adding elements is O(1).
///
/// The AddressSet implementation packs the length with the 0th entry.
///
/// All enumerable sets except Uint8Set use a pop and swap mechanism to remove elements.
/// This means that the iteration order of elements can change between element removals.
library EnumerableSetLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The index must be less than the length.
error IndexOutOfBounds();
/// @dev The value cannot be the zero sentinel.
error ValueIsZeroSentinel();
/// @dev Cannot accommodate a new unique value with the capacity.
error ExceedsCapacity();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A sentinel value to denote the zero value in storage.
/// No elements can be equal to this value.
/// `uint72(bytes9(keccak256(bytes("_ZERO_SENTINEL"))))`.
uint256 private constant _ZERO_SENTINEL = 0xfbb67fda52d4bfb8bf;
/// @dev The storage layout is given by:
/// ```
/// mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED)
/// mstore(0x00, set.slot)
/// let rootSlot := keccak256(0x00, 0x24)
/// mstore(0x20, rootSlot)
/// mstore(0x00, shr(96, shl(96, value)))
/// let positionSlot := keccak256(0x00, 0x40)
/// let valueSlot := add(rootSlot, sload(positionSlot))
/// let valueInStorage := shr(96, sload(valueSlot))
/// let lazyLength := shr(160, shl(160, sload(rootSlot)))
/// ```
uint256 private constant _ENUMERABLE_ADDRESS_SET_SLOT_SEED = 0x978aab92;
/// @dev The storage layout is given by:
/// ```
/// mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED)
/// mstore(0x00, set.slot)
/// let rootSlot := keccak256(0x00, 0x24)
/// mstore(0x20, rootSlot)
/// mstore(0x00, value)
/// let positionSlot := keccak256(0x00, 0x40)
/// let valueSlot := add(rootSlot, sload(positionSlot))
/// let valueInStorage := sload(valueSlot)
/// let lazyLength := sload(not(rootSlot))
/// ```
uint256 private constant _ENUMERABLE_WORD_SET_SLOT_SEED = 0x18fb5864;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev An enumerable address set in storage.
struct AddressSet {
uint256 _spacer;
}
/// @dev An enumerable bytes32 set in storage.
struct Bytes32Set {
uint256 _spacer;
}
/// @dev An enumerable uint256 set in storage.
struct Uint256Set {
uint256 _spacer;
}
/// @dev An enumerable int256 set in storage.
struct Int256Set {
uint256 _spacer;
}
/// @dev An enumerable uint8 set in storage. Useful for enums.
struct Uint8Set {
uint256 data;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GETTERS / SETTERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of elements in the set.
function length(AddressSet storage set) internal view returns (uint256 result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
let rootPacked := sload(rootSlot)
let n := shr(160, shl(160, rootPacked))
result := shr(1, n)
for {} iszero(or(iszero(shr(96, rootPacked)), n)) {} {
result := 1
if iszero(sload(add(rootSlot, result))) { break }
result := 2
if iszero(sload(add(rootSlot, result))) { break }
result := 3
break
}
}
}
/// @dev Returns the number of elements in the set.
function length(Bytes32Set storage set) internal view returns (uint256 result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
let n := sload(not(rootSlot))
result := shr(1, n)
for {} iszero(n) {} {
result := 0
if iszero(sload(add(rootSlot, result))) { break }
result := 1
if iszero(sload(add(rootSlot, result))) { break }
result := 2
if iszero(sload(add(rootSlot, result))) { break }
result := 3
break
}
}
}
/// @dev Returns the number of elements in the set.
function length(Uint256Set storage set) internal view returns (uint256 result) {
result = length(_toBytes32Set(set));
}
/// @dev Returns the number of elements in the set.
function length(Int256Set storage set) internal view returns (uint256 result) {
result = length(_toBytes32Set(set));
}
/// @dev Returns the number of elements in the set.
function length(Uint8Set storage set) internal view returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for { let packed := sload(set.slot) } packed { result := add(1, result) } {
packed := xor(packed, and(packed, add(1, not(packed))))
}
}
}
/// @dev Returns whether `value` is in the set.
function contains(AddressSet storage set, address value) internal view returns (bool result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
value := shr(96, shl(96, value))
if eq(value, _ZERO_SENTINEL) {
mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
revert(0x1c, 0x04)
}
if iszero(value) { value := _ZERO_SENTINEL }
let rootPacked := sload(rootSlot)
for {} 1 {} {
if iszero(shr(160, shl(160, rootPacked))) {
result := 1
if eq(shr(96, rootPacked), value) { break }
if eq(shr(96, sload(add(rootSlot, 1))), value) { break }
if eq(shr(96, sload(add(rootSlot, 2))), value) { break }
result := 0
break
}
mstore(0x20, rootSlot)
mstore(0x00, value)
result := iszero(iszero(sload(keccak256(0x00, 0x40))))
break
}
}
}
/// @dev Returns whether `value` is in the set.
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
if eq(value, _ZERO_SENTINEL) {
mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
revert(0x1c, 0x04)
}
if iszero(value) { value := _ZERO_SENTINEL }
for {} 1 {} {
if iszero(sload(not(rootSlot))) {
result := 1
if eq(sload(rootSlot), value) { break }
if eq(sload(add(rootSlot, 1)), value) { break }
if eq(sload(add(rootSlot, 2)), value) { break }
result := 0
break
}
mstore(0x20, rootSlot)
mstore(0x00, value)
result := iszero(iszero(sload(keccak256(0x00, 0x40))))
break
}
}
}
/// @dev Returns whether `value` is in the set.
function contains(Uint256Set storage set, uint256 value) internal view returns (bool result) {
result = contains(_toBytes32Set(set), bytes32(value));
}
/// @dev Returns whether `value` is in the set.
function contains(Int256Set storage set, int256 value) internal view returns (bool result) {
result = contains(_toBytes32Set(set), bytes32(uint256(value)));
}
/// @dev Returns whether `value` is in the set.
function contains(Uint8Set storage set, uint8 value) internal view returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := and(1, shr(and(0xff, value), sload(set.slot)))
}
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
function add(AddressSet storage set, address value) internal returns (bool result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
value := shr(96, shl(96, value))
if eq(value, _ZERO_SENTINEL) {
mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
revert(0x1c, 0x04)
}
if iszero(value) { value := _ZERO_SENTINEL }
let rootPacked := sload(rootSlot)
for { let n := shr(160, shl(160, rootPacked)) } 1 {} {
mstore(0x20, rootSlot)
if iszero(n) {
let v0 := shr(96, rootPacked)
if iszero(v0) {
sstore(rootSlot, shl(96, value))
result := 1
break
}
if eq(v0, value) { break }
let v1 := shr(96, sload(add(rootSlot, 1)))
if iszero(v1) {
sstore(add(rootSlot, 1), shl(96, value))
result := 1
break
}
if eq(v1, value) { break }
let v2 := shr(96, sload(add(rootSlot, 2)))
if iszero(v2) {
sstore(add(rootSlot, 2), shl(96, value))
result := 1
break
}
if eq(v2, value) { break }
mstore(0x00, v0)
sstore(keccak256(0x00, 0x40), 1)
mstore(0x00, v1)
sstore(keccak256(0x00, 0x40), 2)
mstore(0x00, v2)
sstore(keccak256(0x00, 0x40), 3)
rootPacked := or(rootPacked, 7)
n := 7
}
mstore(0x00, value)
let p := keccak256(0x00, 0x40)
if iszero(sload(p)) {
n := shr(1, n)
result := 1
sstore(p, add(1, n))
if iszero(n) {
sstore(rootSlot, or(3, shl(96, value)))
break
}
sstore(add(rootSlot, n), shl(96, value))
sstore(rootSlot, add(2, rootPacked))
break
}
break
}
}
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
function add(Bytes32Set storage set, bytes32 value) internal returns (bool result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
if eq(value, _ZERO_SENTINEL) {
mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
revert(0x1c, 0x04)
}
if iszero(value) { value := _ZERO_SENTINEL }
for { let n := sload(not(rootSlot)) } 1 {} {
mstore(0x20, rootSlot)
if iszero(n) {
let v0 := sload(rootSlot)
if iszero(v0) {
sstore(rootSlot, value)
result := 1
break
}
if eq(v0, value) { break }
let v1 := sload(add(rootSlot, 1))
if iszero(v1) {
sstore(add(rootSlot, 1), value)
result := 1
break
}
if eq(v1, value) { break }
let v2 := sload(add(rootSlot, 2))
if iszero(v2) {
sstore(add(rootSlot, 2), value)
result := 1
break
}
if eq(v2, value) { break }
mstore(0x00, v0)
sstore(keccak256(0x00, 0x40), 1)
mstore(0x00, v1)
sstore(keccak256(0x00, 0x40), 2)
mstore(0x00, v2)
sstore(keccak256(0x00, 0x40), 3)
n := 7
}
mstore(0x00, value)
let p := keccak256(0x00, 0x40)
if iszero(sload(p)) {
n := shr(1, n)
sstore(add(rootSlot, n), value)
sstore(p, add(1, n))
sstore(not(rootSlot), or(1, shl(1, add(1, n))))
result := 1
break
}
break
}
}
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
function add(Uint256Set storage set, uint256 value) internal returns (bool result) {
result = add(_toBytes32Set(set), bytes32(value));
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
function add(Int256Set storage set, int256 value) internal returns (bool result) {
result = add(_toBytes32Set(set), bytes32(uint256(value)));
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
function add(Uint8Set storage set, uint8 value) internal returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(set.slot)
let mask := shl(and(0xff, value), 1)
sstore(set.slot, or(result, mask))
result := iszero(and(result, mask))
}
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
/// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
function add(AddressSet storage set, address value, uint256 cap)
internal
returns (bool result)
{
if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
/// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
function add(Bytes32Set storage set, bytes32 value, uint256 cap)
internal
returns (bool result)
{
if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
/// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
function add(Uint256Set storage set, uint256 value, uint256 cap)
internal
returns (bool result)
{
if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
/// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
function add(Int256Set storage set, int256 value, uint256 cap) internal returns (bool result) {
if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
}
/// @dev Adds `value` to the set. Returns whether `value` was not in the set.
/// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`.
function add(Uint8Set storage set, uint8 value, uint256 cap) internal returns (bool result) {
if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity();
}
/// @dev Removes `value` from the set. Returns whether `value` was in the set.
function remove(AddressSet storage set, address value) internal returns (bool result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
value := shr(96, shl(96, value))
if eq(value, _ZERO_SENTINEL) {
mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
revert(0x1c, 0x04)
}
if iszero(value) { value := _ZERO_SENTINEL }
let rootPacked := sload(rootSlot)
for { let n := shr(160, shl(160, rootPacked)) } 1 {} {
if iszero(n) {
result := 1
if eq(shr(96, rootPacked), value) {
sstore(rootSlot, sload(add(rootSlot, 1)))
sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
sstore(add(rootSlot, 2), 0)
break
}
if eq(shr(96, sload(add(rootSlot, 1))), value) {
sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
sstore(add(rootSlot, 2), 0)
break
}
if eq(shr(96, sload(add(rootSlot, 2))), value) {
sstore(add(rootSlot, 2), 0)
break
}
result := 0
break
}
mstore(0x20, rootSlot)
mstore(0x00, value)
let p := keccak256(0x00, 0x40)
let position := sload(p)
if iszero(position) { break }
n := sub(shr(1, n), 1)
if iszero(eq(sub(position, 1), n)) {
let lastValue := shr(96, sload(add(rootSlot, n)))
sstore(add(rootSlot, sub(position, 1)), shl(96, lastValue))
mstore(0x00, lastValue)
sstore(keccak256(0x00, 0x40), position)
}
sstore(rootSlot, or(shl(96, shr(96, sload(rootSlot))), or(shl(1, n), 1)))
sstore(p, 0)
result := 1
break
}
}
}
/// @dev Removes `value` from the set. Returns whether `value` was in the set.
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
if eq(value, _ZERO_SENTINEL) {
mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
revert(0x1c, 0x04)
}
if iszero(value) { value := _ZERO_SENTINEL }
for { let n := sload(not(rootSlot)) } 1 {} {
if iszero(n) {
result := 1
if eq(sload(rootSlot), value) {
sstore(rootSlot, sload(add(rootSlot, 1)))
sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
sstore(add(rootSlot, 2), 0)
break
}
if eq(sload(add(rootSlot, 1)), value) {
sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
sstore(add(rootSlot, 2), 0)
break
}
if eq(sload(add(rootSlot, 2)), value) {
sstore(add(rootSlot, 2), 0)
break
}
result := 0
break
}
mstore(0x20, rootSlot)
mstore(0x00, value)
let p := keccak256(0x00, 0x40)
let position := sload(p)
if iszero(position) { break }
n := sub(shr(1, n), 1)
if iszero(eq(sub(position, 1), n)) {
let lastValue := sload(add(rootSlot, n))
sstore(add(rootSlot, sub(position, 1)), lastValue)
mstore(0x00, lastValue)
sstore(keccak256(0x00, 0x40), position)
}
sstore(not(rootSlot), or(shl(1, n), 1))
sstore(p, 0)
result := 1
break
}
}
}
/// @dev Removes `value` from the set. Returns whether `value` was in the set.
function remove(Uint256Set storage set, uint256 value) internal returns (bool result) {
result = remove(_toBytes32Set(set), bytes32(value));
}
/// @dev Removes `value` from the set. Returns whether `value` was in the set.
function remove(Int256Set storage set, int256 value) internal returns (bool result) {
result = remove(_toBytes32Set(set), bytes32(uint256(value)));
}
/// @dev Removes `value` from the set. Returns whether `value` was in the set.
function remove(Uint8Set storage set, uint8 value) internal returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(set.slot)
let mask := shl(and(0xff, value), 1)
sstore(set.slot, and(result, not(mask)))
result := iszero(iszero(and(result, mask)))
}
}
/// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
function update(AddressSet storage set, address value, bool isAdd, uint256 cap)
internal
returns (bool)
{
return isAdd ? add(set, value, cap) : remove(set, value);
}
/// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
function update(Bytes32Set storage set, bytes32 value, bool isAdd, uint256 cap)
internal
returns (bool)
{
return isAdd ? add(set, value, cap) : remove(set, value);
}
/// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
function update(Uint256Set storage set, uint256 value, bool isAdd, uint256 cap)
internal
returns (bool)
{
return isAdd ? add(set, value, cap) : remove(set, value);
}
/// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
function update(Int256Set storage set, int256 value, bool isAdd, uint256 cap)
internal
returns (bool)
{
return isAdd ? add(set, value, cap) : remove(set, value);
}
/// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`.
function update(Uint8Set storage set, uint8 value, bool isAdd, uint256 cap)
internal
returns (bool)
{
return isAdd ? add(set, value, cap) : remove(set, value);
}
/// @dev Returns all of the values in the set.
/// Note: This can consume more gas than the block gas limit for large sets.
function values(AddressSet storage set) internal view returns (address[] memory result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
let zs := _ZERO_SENTINEL
let rootPacked := sload(rootSlot)
let n := shr(160, shl(160, rootPacked))
result := mload(0x40)
let o := add(0x20, result)
let v := shr(96, rootPacked)
mstore(o, mul(v, iszero(eq(v, zs))))
for {} 1 {} {
if iszero(n) {
if v {
n := 1
v := shr(96, sload(add(rootSlot, n)))
if v {
n := 2
mstore(add(o, 0x20), mul(v, iszero(eq(v, zs))))
v := shr(96, sload(add(rootSlot, n)))
if v {
n := 3
mstore(add(o, 0x40), mul(v, iszero(eq(v, zs))))
}
}
}
break
}
n := shr(1, n)
for { let i := 1 } lt(i, n) { i := add(i, 1) } {
v := shr(96, sload(add(rootSlot, i)))
mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs))))
}
break
}
mstore(result, n)
mstore(0x40, add(o, shl(5, n)))
}
}
/// @dev Returns all of the values in the set.
/// Note: This can consume more gas than the block gas limit for large sets.
function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
let zs := _ZERO_SENTINEL
let n := sload(not(rootSlot))
result := mload(0x40)
let o := add(0x20, result)
for {} 1 {} {
if iszero(n) {
let v := sload(rootSlot)
if v {
n := 1
mstore(o, mul(v, iszero(eq(v, zs))))
v := sload(add(rootSlot, n))
if v {
n := 2
mstore(add(o, 0x20), mul(v, iszero(eq(v, zs))))
v := sload(add(rootSlot, n))
if v {
n := 3
mstore(add(o, 0x40), mul(v, iszero(eq(v, zs))))
}
}
}
break
}
n := shr(1, n)
for { let i := 0 } lt(i, n) { i := add(i, 1) } {
let v := sload(add(rootSlot, i))
mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs))))
}
break
}
mstore(result, n)
mstore(0x40, add(o, shl(5, n)))
}
}
/// @dev Returns all of the values in the set.
/// Note: This can consume more gas than the block gas limit for large sets.
function values(Uint256Set storage set) internal view returns (uint256[] memory result) {
result = _toUints(values(_toBytes32Set(set)));
}
/// @dev Returns all of the values in the set.
/// Note: This can consume more gas than the block gas limit for large sets.
function values(Int256Set storage set) internal view returns (int256[] memory result) {
result = _toInts(values(_toBytes32Set(set)));
}
/// @dev Returns all of the values in the set.
function values(Uint8Set storage set) internal view returns (uint8[] memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let ptr := add(result, 0x20)
let o := 0
for { let packed := sload(set.slot) } packed {} {
if iszero(and(packed, 0xffff)) {
o := add(o, 16)
packed := shr(16, packed)
continue
}
mstore(ptr, o)
ptr := add(ptr, shl(5, and(packed, 1)))
o := add(o, 1)
packed := shr(1, packed)
}
mstore(result, shr(5, sub(ptr, add(result, 0x20))))
mstore(0x40, ptr)
}
}
/// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
function at(AddressSet storage set, uint256 i) internal view returns (address result) {
bytes32 rootSlot = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
result := shr(96, sload(add(rootSlot, i)))
result := mul(result, iszero(eq(result, _ZERO_SENTINEL)))
}
if (i >= length(set)) revert IndexOutOfBounds();
}
/// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
function at(Bytes32Set storage set, uint256 i) internal view returns (bytes32 result) {
result = _rootSlot(set);
/// @solidity memory-safe-assembly
assembly {
result := sload(add(result, i))
result := mul(result, iszero(eq(result, _ZERO_SENTINEL)))
}
if (i >= length(set)) revert IndexOutOfBounds();
}
/// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
function at(Uint256Set storage set, uint256 i) internal view returns (uint256 result) {
result = uint256(at(_toBytes32Set(set), i));
}
/// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
function at(Int256Set storage set, uint256 i) internal view returns (int256 result) {
result = int256(uint256(at(_toBytes32Set(set), i)));
}
/// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds.
function at(Uint8Set storage set, uint256 i) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
let packed := sload(set.slot)
for {} 1 {
mstore(0x00, 0x4e23d035) // `IndexOutOfBounds()`.
revert(0x1c, 0x04)
} {
if iszero(lt(i, 256)) { continue }
for { let j := 0 } iszero(eq(i, j)) {} {
packed := xor(packed, and(packed, add(1, not(packed))))
j := add(j, 1)
}
if iszero(packed) { continue }
break
}
// Find first set subroutine, optimized for smaller bytecode size.
let x := and(packed, add(1, not(packed)))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
// For the lower 5 bits of the result, use a De Bruijn lookup.
// forgefmt: disable-next-item
result := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the root slot.
function _rootSlot(AddressSet storage s) private pure returns (bytes32 r) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED)
mstore(0x00, s.slot)
r := keccak256(0x00, 0x24)
}
}
/// @dev Returns the root slot.
function _rootSlot(Bytes32Set storage s) private pure returns (bytes32 r) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED)
mstore(0x00, s.slot)
r := keccak256(0x00, 0x24)
}
}
/// @dev Casts to a Bytes32Set.
function _toBytes32Set(Uint256Set storage s) private pure returns (Bytes32Set storage c) {
/// @solidity memory-safe-assembly
assembly {
c.slot := s.slot
}
}
/// @dev Casts to a Bytes32Set.
function _toBytes32Set(Int256Set storage s) private pure returns (Bytes32Set storage c) {
/// @solidity memory-safe-assembly
assembly {
c.slot := s.slot
}
}
/// @dev Casts to a uint256 array.
function _toUints(bytes32[] memory a) private pure returns (uint256[] memory c) {
/// @solidity memory-safe-assembly
assembly {
c := a
}
}
/// @dev Casts to a int256 array.
function _toInts(bytes32[] memory a) private pure returns (int256[] memory c) {
/// @solidity memory-safe-assembly
assembly {
c := a
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
contract PythStructs {
// A price with a degree of uncertainty, represented as a price +- a confidence interval.
//
// The confidence interval roughly corresponds to the standard error of a normal distribution.
// Both the price and confidence are stored in a fixed-point numeric representation,
// `x * (10^expo)`, where `expo` is the exponent.
//
// Please refer to the documentation at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how
// to how this price safely.
struct Price {
// Price
int64 price;
// Confidence interval around the price
uint64 conf;
// Price exponent
int32 expo;
// Unix timestamp describing when the price was published
uint publishTime;
}
// PriceFeed represents a current aggregate price from pyth publisher feeds.
struct PriceFeed {
// The price ID.
bytes32 id;
// Latest available price
Price price;
// Latest available exponentially-weighted moving average price
Price emaPrice;
}
struct TwapPriceFeed {
// The price ID.
bytes32 id;
// Start time of the TWAP
uint64 startTime;
// End time of the TWAP
uint64 endTime;
// TWAP price
Price twap;
// Down slot ratio represents the ratio of price feed updates that were missed or unavailable
// during the TWAP period, expressed as a fixed-point number between 0 and 1e6 (100%).
// For example:
// - 0 means all price updates were available
// - 500_000 means 50% of updates were missed
// - 1_000_000 means all updates were missed
// This can be used to assess the quality/reliability of the TWAP calculation.
// Applications should define a maximum acceptable ratio (e.g. 100000 for 10%)
// and revert if downSlotsRatio exceeds it.
uint32 downSlotsRatio;
}
// Information used to calculate time-weighted average prices (TWAP)
struct TwapPriceInfo {
// slot 1
int128 cumulativePrice;
uint128 cumulativeConf;
// slot 2
uint64 numDownSlots;
uint64 publishSlot;
uint64 publishTime;
uint64 prevPublishTime;
// slot 3
int32 expo;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @title IPythEvents contains the events that Pyth contract emits.
/// @dev This interface can be used for listening to the updates for off-chain and testing purposes.
interface IPythEvents {
/// @dev Emitted when the price feed with `id` has received a fresh update.
/// @param id The Pyth Price Feed ID.
/// @param publishTime Publish time of the given price update.
/// @param price Price of the given price update.
/// @param conf Confidence interval of the given price update.
event PriceFeedUpdate(
bytes32 indexed id,
uint64 publishTime,
int64 price,
uint64 conf
);
/// @dev Emitted when the TWAP price feed with `id` has received a fresh update.
/// @param id The Pyth Price Feed ID.
/// @param startTime Start time of the TWAP.
/// @param endTime End time of the TWAP.
/// @param twapPrice Price of the TWAP.
/// @param twapConf Confidence interval of the TWAP.
/// @param downSlotsRatio Down slot ratio of the TWAP.
event TwapPriceFeedUpdate(
bytes32 indexed id,
uint64 startTime,
uint64 endTime,
int64 twapPrice,
uint64 twapConf,
uint32 downSlotsRatio
);
}{
"optimizer": {
"enabled": true,
"mode": "3",
"fallback_to_optimizing_for_size": false
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"detectMissingLibraries": false,
"forceEVMLA": false,
"enableEraVMExtensions": false,
"codegen": "evmla",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyAtMaxFacility","type":"error"},{"inputs":[],"name":"AlreadyPurchasedInitialFactory","type":"error"},{"inputs":[],"name":"CantBuyNewFacilityYet","type":"error"},{"inputs":[],"name":"CantModifyStarterFacility","type":"error"},{"inputs":[],"name":"CantModifyStarterMiner","type":"error"},{"inputs":[],"name":"IncorrectValue","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidFacilityIndex","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidMinerCoordinates","type":"error"},{"inputs":[],"name":"InvalidMinerIndex","type":"error"},{"inputs":[],"name":"InvalidReferrer","type":"error"},{"inputs":[],"name":"MinerFullUpdated","type":"error"},{"inputs":[],"name":"MinerInMarket","type":"error"},{"inputs":[],"name":"MinerInMining","type":"error"},{"inputs":[],"name":"MinerInStore","type":"error"},{"inputs":[],"name":"MinerNotInProduction","type":"error"},{"inputs":[],"name":"MiningHasntStarted","type":"error"},{"inputs":[],"name":"NeedToInitializeFacility","type":"error"},{"inputs":[],"name":"NewFacilityNotInProduction","type":"error"},{"inputs":[],"name":"NoRewardsPending","type":"error"},{"inputs":[],"name":"NonExistentFacility","type":"error"},{"inputs":[],"name":"NonExistentMiner","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotListedMinerOnMarketplace","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PlayerDoesNotOwnMiner","type":"error"},{"inputs":[],"name":"TokenNotTradeable","type":"error"},{"inputs":[],"name":"TooPoor","type":"error"},{"inputs":[],"name":"WithdrawFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"}],"name":"FacilityBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCost","type":"uint256"}],"name":"FacilityCostChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"indexed":false,"internalType":"bool","name":"inProduction","type":"bool"}],"name":"FacilityProductionToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"}],"name":"InitialFacilityPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"ListedForSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minerId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"x","type":"uint256"}],"name":"MinerBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minerId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"}],"name":"MinerBoughtOnMarketplace","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCost","type":"uint256"}],"name":"MinerCostChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"bool","name":"inProduction","type":"bool"}],"name":"MinerProductionToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"secondHandPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minerId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"x","type":"uint256"}],"name":"MinerSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"level","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minerId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"x","type":"uint256"}],"name":"MinerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"}],"name":"MiningStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"},{"indexed":false,"internalType":"bool","name":"inProduction","type":"bool"}],"name":"NewFacilityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"minerIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"hashRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"},{"indexed":false,"internalType":"bool","name":"inProduction","type":"bool"}],"name":"NewMinerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"playerHashrate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"playerPendingRewards","type":"uint256"}],"name":"PlayerHashrateDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"playerHashrate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"playerPendingRewards","type":"uint256"}],"name":"PlayerHashrateIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"x","type":"uint256"}],"name":"StartedMining","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"StoppedMining","type":"event"},{"inputs":[],"name":"HALVING_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_HASHCOIN_PER_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARDS_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STARTER_FACILITY_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STARTER_MINER_INDEX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxMiners","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"inProduction","type":"bool"}],"name":"addFacility","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"hashrate","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"inProduction","type":"bool"}],"name":"addMiner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"blocksUntilNextHalving","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnPct","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerIndex","type":"uint256"}],"name":"buyMiner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"buyMinerFromMarket","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"buyNewFacility","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"cancelListForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"internalType":"uint256","name":"newCost","type":"uint256"}],"name":"changeFacilityCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerIndex","type":"uint256"},{"internalType":"uint256","name":"newCost","type":"uint256"}],"name":"changeMinerCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativeHashcoinPerHash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"facilities","outputs":[{"internalType":"uint256","name":"maxMiners","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"inProduction","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"facilityCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEthPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHashcoinPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInitialFacilityPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinersOnMarketplace","outputs":[{"components":[{"internalType":"uint256","name":"minerIndex","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"hashrate","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"isListedSell","type":"bool"},{"internalType":"uint256","name":"sellPrice","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"inProduction","type":"bool"}],"internalType":"struct Miner[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextInitialFacilityPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"}],"name":"getPlayerMinersPaginated","outputs":[{"components":[{"internalType":"uint256","name":"minerIndex","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"hashrate","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"isListedSell","type":"bool"},{"internalType":"uint256","name":"sellPrice","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"inProduction","type":"bool"}],"internalType":"struct Miner[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"getReferrals","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"}],"name":"getTokenAmountFromEthAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"halvingOvershoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hashcoin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hashtoshi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialMinerCnt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"initializedStarterFacility","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTokenTradeable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastFacilityUpgradeTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRewardBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"listForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lordztoshi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPythPriceAge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"miners","outputs":[{"internalType":"uint256","name":"minerIndex","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"hashrate","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"isListedSell","type":"bool"},{"internalType":"uint256","name":"sellPrice","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"inProduction","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minersListedOnMarketplace","outputs":[{"internalType":"uint256","name":"_spacer","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"miningHasStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ownerToFacility","outputs":[{"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"internalType":"uint256","name":"maxMiners","type":"uint256"},{"internalType":"uint256","name":"currMiners","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerHashcoinDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"playerHashcoinPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerHashrate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"playerMinersId","outputs":[{"internalType":"uint256","name":"minerIndex","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"hashrate","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"},{"internalType":"bool","name":"isListedSell","type":"bool"},{"internalType":"uint256","name":"sellPrice","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"inProduction","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerMinersOwned","outputs":[{"internalType":"uint256","name":"_spacer","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"playerOccupiedCoords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"printoshi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"purchaseInitialFacility","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"purchaseInitialFacilityFree","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pythNetwork","outputs":[{"internalType":"contract IPyth","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pythPriceId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralBonusPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referrals","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"referredUsers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"removeMiner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"burn","type":"uint256"}],"name":"setBurnPct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cooldown","type":"uint256"}],"name":"setCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_halvingInterval","type":"uint256"}],"name":"setHalvingInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hashcoin","type":"address"}],"name":"setHashcoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_hashtoshi","type":"address"}],"name":"setHashtoshi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialHashcoinPerBlock","type":"uint256"}],"name":"setInitialHashcoinPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_lordztoshi","type":"address"}],"name":"setLordztoshi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_marketFee","type":"uint256"}],"name":"setMarketFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_pool","type":"address"},{"internalType":"bool","name":"_isTokenTradeable","type":"bool"}],"name":"setPoolInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_printoshi","type":"address"}],"name":"setPrintoshi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pythAddress","type":"address"},{"internalType":"uint256","name":"_maxPythPriceAge","type":"uint256"},{"internalType":"bytes32","name":"_priceId","type":"bytes32"}],"name":"setPyth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setReferralFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"},{"internalType":"uint256","name":"x","type":"uint256"}],"name":"startMining","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"stopMining","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"timeUntilNextFacilityUpgrade","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"facilityIndex","type":"uint256"},{"internalType":"bool","name":"inProduction","type":"bool"}],"name":"toggleFacilityProduction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerIndex","type":"uint256"},{"internalType":"bool","name":"inProduction","type":"bool"}],"name":"toggleMinerProduction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalHashrate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniqueMinerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"updateMiner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wethAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"withdrawHashcoin","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
9c4d535b000000000000000000000000000000000000000000000000000000000000000001000a35d86551c564c42f1476ad60767b9ee7582dac16e8564fed7b7f5998d600000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x00010000000000020014000000000002000000000301034f00000000000103550000008001000039000000400010043f00000001002001900000002b0000c13d00000060013002700000092501100197000000040010008c00001dc50000413d000000000203043b000000e002200270000009270020009c000000330000213d000009650020009c0000007b0000213d000009840020009c000000a20000a13d000009850020009c000000f50000213d0000098d0020009c000002e90000213d000009910020009c0000075f0000613d000009920020009c000009a60000613d000009930020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d248e211e0000040f00000004010000390000000001100367000000000101043b0000001e02000039000000000012041b00000000010000190000248f0001042e0000000001000416000000000001004b00001dc50000c13d00000020010000390000010000100443000001200000044300000926010000410000248f0001042e000009280020009c0000008c0000213d000009470020009c000000b10000a13d000009480020009c0000012f0000213d000009500020009c000002f40000213d000009540020009c000007640000613d000009550020009c000009b20000613d000009560020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001103000029000009a40030009c00000aa90000613d00000a1602100167000000000003004b0000000004030019000009a404006041000000000202041a000000000002004b001000000004001d000011f30000c13d000000000201041a000000000042004b000012070000613d0000000102100039000000000202041a000000100020006c000012070000613d0000000201100039000000000101041a000000100010006c000012030000c13d000012070000013d000009660020009c000000cc0000a13d000009670020009c0000013c0000213d0000096f0020009c000002ff0000213d000009730020009c000007690000613d000009740020009c000009b90000613d000009750020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d00000021010000390000097e0000013d000009290020009c000000db0000a13d0000092a0020009c000001af0000213d000009320020009c0000030a0000213d000009360020009c0000078e0000613d000009370020009c000009d20000613d000009380020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000000000010043f0000001601000039000008b60000013d000009940020009c000001dc0000a13d000009950020009c0000027f0000213d000009990020009c000005370000613d0000099a0020009c000008fa0000613d0000099b0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000002601000039000009030000013d000009570020009c000001eb0000a13d000009580020009c000002920000213d0000095c0020009c000005760000613d0000095d0020009c000008ff0000613d0000095e0020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d248e211e0000040f000000000100041a000009ad0110019700000011011001af000000000010041b00000000010000190000248f0001042e000009760020009c000001f80000a13d000009770020009c000002c90000213d0000097b0020009c000005840000613d0000097c0020009c000009070000613d0000097d0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d00000003010000390000097e0000013d000009390020009c000002590000a13d0000093a0020009c000002dc0000213d0000093e0020009c000005890000613d0000093f0020009c0000091b0000613d000009400020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001801000039000000200010043f00000040020000390000000001000019248e246f0000040f00000abe0000013d000009860020009c000003150000213d0000098a0020009c000007930000613d0000098b0020009c00000a200000613d0000098c0020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000b00000001001d000009a60010009c00001dc50000213d00000000030004150000000501000039000000000101041a000000ff001001900000000001000019000009170000613d000a00000003001d0000000b01000039000000000101041a000e00000001001d000000000001004b00000ce80000c13d0000000b01000029000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000e02000039000000000202041a000009c70020009c0000163c0000213d000000000101041a000009c7022000990000012b0000613d00000a1603200129000000000013004b00000bb50000413d00000000011200a9000009c70110012a0000000a03000029000009170000013d000009490020009c000003450000213d0000094d0020009c0000079e0000613d0000094e0020009c00000a380000613d0000094f0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d00000002010000390000097e0000013d000009680020009c000003500000213d0000096c0020009c000007ae0000613d0000096d0020009c00000a470000613d0000096e0020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000000000010043f0000001301000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400300043d000009c20030009c000016ca0000213d000000000101043b0000014002300039000000400020043f000000000201041a00000000042304360000000102100039000000000202041a000d00000004001d00000000002404350000000202100039000000000202041a0000004004300039000e00000004001d00000000002404350000000302100039000000000202041a0000006004300039000a00000004001d00000000002404350000000402100039000000000202041a0000008004300039000800000004001d00000000002404350000000502100039000000000202041a000000a004300039000f00000004001d00000000002404350000000602100039000000000202041a000000ff002001900000000002000039000000010200c039000000c004300039000700000004001d00000000002404350000000702100039000000000202041a000000e004300039000900000004001d00000000002404350000000801100039000000000101041a0000010004300039000009a602100197000c00000004001d0000000000240435000b00000003001d0000012002300039000009af001001980000000001000039000000010100c039001000000002001d00000000001204350000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000110010006b0000027b0000213d00000010010000290000000001010433000000000001004b000014360000613d0000002501000039000000000101041a000009af001001980000143a0000c13d00000a0c01000041000000000010043f000009bd0100004100002490000104300000092b0020009c0000036d0000213d0000092f0020009c000007b30000613d000009300020009c00000a800000613d000009310020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d0000002402300370000000000202043b001100000002001d000000000010043f0000001c01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000110020006b00001dc50000813d0000001102000029248e1e270000040f0000000302200210000000000101041a000000000121022f000009a601100197000000ff0020008c000000000100201900000b080000013d0000099c0020009c0000039d0000a13d0000099d0020009c000003fc0000613d0000099e0020009c000004f70000613d0000099f0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000000701000039000000000101041a000000f90010008c0000057f0000013d0000095f0020009c000003a60000a13d000009600020009c000004010000613d000009610020009c0000050d0000613d000009620020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000000801000039000009030000013d0000097e0020009c000003af0000a13d0000097f0020009c000004140000613d000009800020009c000005220000613d000009810020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001c01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000301041a000000400200043d001000000002001d000f00000003001d0000000002320436001100000002001d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009ba011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000f05000029000000000005004b00000011060000290000000002060019000002350000613d000000000101043b00000000030000190000000002060019000000000401041a000009a604400197000000000242043600000001011000390000000103300039000000000053004b0000022e0000413d000000100300002900000000013200490000001f0110003900000a17021001970000000001320019000000000021004b00000000020000390000000102004039000009aa0010009c000016ca0000213d0000000100200190000016ca0000c13d000000400010043f00000020020000390000000002210436000000000303043300000000003204350000004002100039000000000003004b000002500000613d00000000040000190000000065060434000009a60550019700000000025204360000000104400039000000000034004b0000024a0000413d0000000002120049000009250020009c00000925020080410000006002200210000009250010009c00000925010080410000004001100210000000000112019f0000248f0001042e000009410020009c000003ec0000a13d000009420020009c0000043e0000613d000009430020009c0000052e0000613d000009440020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000000401300370000000000101043b001100000001001d0000002401300370000000000101043b001000000001001d000000010010008c00001dc50000213d000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000001102000029000000000002004b0000027b0000613d0000000801000039000000000101041a000000000012004b00000ffc0000a13d000009f101000041000000000010043f000009bd010000410000249000010430000009960020009c0000059c0000613d000009970020009c000009280000613d000009980020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d248e211e0000040f000000030100003900000ad10000013d000009590020009c000005a80000613d0000095a0020009c000009340000613d0000095b0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d000009cf01000041000000000401041a000009d00340019800000000010000390000000101006039000009aa02400198000002b90000613d000000010020008c00000b230000c13d001000000004001d001100000003001d000009d1010000410000000000100443000000000100041000000004001004430000000001000414000009250010009c0000092501008041000000c001100210000009d2011001c70000800202000039248e24890000040f0000000100200190000019a30000613d000000000101043b000000000001004b0000000001000039000000010100603900000011030000290000001004000029000000010010019000000b230000613d000009d30140019700000001011001bf000009d402400197000009d5022001c7000000000003004b000000000201c019000009cf01000041000000000021041b000009d00020019800000c6d0000c13d000009df01000041000000000010043f000009bd010000410000249000010430000009780020009c000005b40000613d000009790020009c0000097a0000613d0000097a0020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d248e211e0000040f00000004010000390000000001100367000000000101043b0000000d02000039000000000012041b00000000010000190000248f0001042e0000093b0020009c000006290000613d0000093c0020009c000009830000613d0000093d0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000002501000039000000000101041a000009af0010019800000ac00000013d0000098e0020009c000008820000613d0000098f0020009c00000aad0000613d000009900020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000000701000039000009030000013d000009510020009c0000088f0000613d000009520020009c00000aba0000613d000009530020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000000f01000039000009030000013d000009700020009c000008940000613d000009710020009c000003f50000613d000009720020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000000b01000039000009030000013d000009330020009c000008ad0000613d000009340020009c00000ac50000613d000009350020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000002301000039000009030000013d000009870020009c000008d70000613d000009880020009c00000ad70000613d000009890020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001104000029000000000004004b00000edc0000613d000009a40040009c000000000204001900000aa90000613d00000edd0000013d0000094a0020009c000008de0000613d0000094b0020009c00000af10000613d0000094c0020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000001f01000039000009030000013d000009690020009c000008e30000613d0000096a0020009c00000b040000613d0000096b0020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000002401300370000000000401043b0000000401300370000000000301043b000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000000901000039000000000101041a000000000013004b00000bfb0000a13d000009e801000041000000000010043f000009bd0100004100002490000104300000092c0020009c000003f50000613d0000092d0020009c00000b0f0000613d0000092e0020009c00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001104000029000009a40040009c00000aa90000613d00000a1602100167000000000004004b0000000003040019000009a403006041000000000202041a000000000002004b001000000003001d00000c760000c13d000000000201041a000000000032004b00000c8a0000613d0000000102100039000000000202041a000000000032004b00000c8a0000613d0000000201100039000000000101041a000000000031004b00000c8a0000613d00000c860000013d000009a00020009c0000047a0000613d000009a10020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d0000002001000039000009030000013d000009630020009c000004a30000613d000009640020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d00000001010000390000097e0000013d000009820020009c000004a80000613d000009830020009c00001dc50000c13d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001103000029000009a40030009c00000aa90000613d00000a1602100167000000000003004b000009a403006041000000000202041a000000000002004b001000000003001d000010210000c13d000000000201041a000000000032004b000010300000613d0000000102100039000000000202041a000000100020006c000010300000613d0000000201100039000000000101041a000000100010006c000012030000c13d000010300000013d000009450020009c000004dc0000613d000009460020009c00001dc50000c13d0000000001000416000000000001004b00001dc50000c13d000000000100041a0000097f0000013d0000000001000416000000000001004b00001dc50000c13d0000000101000039000000800010043f000009b7010000410000248f0001042e0000000001000416000000000001004b00001dc50000c13d0000002701000039000009030000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009b102000041000000000202041a000009a6032001970000000002000411000000000023004b00000b1e0000c13d000009e40010009c000005980000813d0000000e02000039000000000012041b00000000010000190000248f0001042e000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d000009e1010000410000000702000039000000000202041a000000fa0020008c000004230000413d000002ed0020008c000009e301000041000009e2010020410000000002000416000000000012004b00000ce40000c13d0000000001000411000000000010043f0000001801000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000ff0010019000000c340000c13d0000000001000411000000110010006b000012ab0000c13d000009fa01000041000000000010043f000009bd0100004100002490000104300000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000002401300370000000000101043b001000000001001d0000000401300370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001104000029000009a40040009c00000aa90000613d000000000004004b0000000002040019000009a40200604100000a1603100167000000000303041a000000000003004b00000e080000c13d000000000301041a000000000023004b00000e180000613d0000000103100039000000000303041a000000000023004b00000e180000613d0000000201100039000000000101041a000000000021004b000012030000c13d00000e180000013d0000000001000416000000000001004b00001dc50000c13d000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b00000a1601200167000000000301041a000000000003004b00000b690000c13d0000000001000415000000140110008a0000000501100210000000000302041a000000000003004b000000000600001900000b6f0000613d0000000201200039000000000101041a0000000102200039000000000202041a000000000001004b00000003060000390000000206006039000000000002004b00000001060060390000000001000415000000120110008a000000050110021000000b6f0000013d0000000001000416000000000001004b00001dc50000c13d0000000901000039000009030000013d0000000001000416000000000001004b00001dc50000c13d000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d000009fc010000410000000000100443000000000100041000000004001004430000000001000414000009250010009c0000092501008041000000c001100210000009d2011001c70000800a02000039248e24890000040f0000000100200190000019a30000613d000000000301043b0000000105000039000000000105041a000009a604100197000000000003004b00000c1f0000c13d001100000005001d001000000003001d0000000001000414000f00000000001d000009250010009c0000092501008041000000c0011002100000000002040019248e24840000040f000e00000002001d0000006002100270000009250220019800000d190000c13d0000000201000039000000000101041a000009a6041001970000000001000414000009250010009c0000092501008041000000c001100210000000110000006b00000fb50000613d000000000204001900000fb90000013d0000000002000416000000000002004b00001dc50000c13d000000640010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d248e211e0000040f0000002101000039000000000201041a000009ad0220019700000011022001af000000000021041b00000000010003670000002402100370000000000202043b0000002203000039000000000023041b0000004401100370000000000101043b0000002302000039000000000012041b00000000010000190000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000000000010043f0000001401000039000000200010043f00000040020000390000000001000019248e246f0000040f0000000102100039000000000302041a000000000201041a0000000201100039000000000101041a000000ff0410018f0000008001000039248e1e010000040f000008d10000013d0000000001000416000000000001004b00001dc50000c13d000009b101000041000000000201041a000009a6032001970000000005000411000000000053004b00000b270000c13d000009ad02200197000000000021041b0000000001000414000009250010009c0000092501008041000000c001100210000009a7011001c70000800d020000390000000303000039000009d6040000410000000006000019000011570000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f000000110100003900000afc0000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b248e1f130000040f00000b080000013d0000000002000416000000000002004b00001dc50000c13d000000640010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d0000002402300370000000000202043b000d00000002001d0000004402300370000000000202043b001100000002001d0000000002000415000900000002001d000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b000009a201000041000000040010043f001000000002001d000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b00000a1602100167000000000202041a000000000002004b000010740000c13d000000000201041a000000000002004b0000000002000039000000010200c039000010750000613d0000000103100039000000000303041a000000000003004b000010750000613d0000000201100039000000000101041a000000000001004b00000003020000390000000202006039000010750000013d0000000001000416000000000001004b00001dc50000c13d000009e1010000410000000702000039000000000202041a000000fa0020008c00000b010000413d000002ed0020008c000009e301000041000009e201002041000000800010043f000009b7010000410000248f0001042e0000000001000416000000000001004b00001dc50000c13d0000000401000039000009030000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009b102000041000000000202041a000009a6032001970000000002000411000000000023004b00000b1e0000c13d000009c70010009c00000bb90000a13d000009e501000041000000000010043f000009bd0100004100002490000104300000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001d0100003900000afc0000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001a0100003900000afc0000013d0000000002000416000000000002004b00001dc50000c13d000000640010008c00001dc50000413d0000004401300370000000000101043b001100000001001d000000010010008c00001dc50000213d0000000401300370000000000401043b0000002401300370000000000301043b000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000000802000039000000000102041a000000010110003a0000163c0000613d000000000012041b000001c002000039000000400020043f000000800010043f000000a00000043f000000c00000043f001000000004001d000000e00040043f0000000102000039000001000020043f000f00000003001d000001200030043f000001400000043f000001600000043f000001800000043f0000001102000029000001a00020043f000000000010043f0000001301000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000800200043d000000000021041b0000000102100039000000a00300043d000000000032041b0000000202100039000000c00300043d000000000032041b0000000302100039000000e00300043d000000000032041b0000000402100039000001000300043d000000000032041b0000000502100039000001200300043d000000000032041b0000000602100039000000000402041a00000a1803400197000001400400043d000000000004004b000000010330c1bf000000000032041b0000000702100039000001600300043d000000000032041b0000000801100039000001800200043d000009a602200197000000000301041a000009c303300197000000000223019f000001a00300043d000000000003004b000009c4030000410000000003006019000000000232019f000000000021041b0000000801000039000000000501041a000000400100043d00000040021000390000001103000029000000000032043500000020021000390000000f03000029000000000032043500000010020000290000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009c5011001c70000800d020000390000000203000039000009f504000041000011570000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000001101000029000000000010043f0000001801000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000ff0010019000000c340000c13d0000001101000029000000000010043f0000001801000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a180220019700000001022001bf000000000021041b0000000101000039000000000010043f0000001401000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400200043d001000000002001d000009be0020009c000016ca0000213d000000000101043b00000010040000290000006002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a000000000032043500000040024000390000000201100039000000000101041a000000ff001001900000000001000039000000010100c03900000000001204350000001101000029000000000010043f0000001701000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b0000000101000039000000000012041b00000010010000290000000001010433001000000002001d0000000102200039000000000012041b0000001101000029000000000010043f0000001a01000039000000200010043f000009bf0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b000f00000001001d0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000f02000029000000000021041b000000400100043d000f00000001001d0000000001000414000009250010009c0000092501008041000000c001100210000009a7011001c70000800d020000390000000203000039000009c1040000410000001105000029248e24840000040f000000010020019000001dc50000613d0000000101000039000000000010043f0000001301000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000f02000029000009c20020009c000016ca0000213d000000000101043b0000000f040000290000014002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000e00000003001d00000000002304350000000302100039000000000202041a0000006003400039000c00000003001d00000000002304350000000402100039000000000202041a0000008003400039000b00000003001d00000000002304350000000502100039000000000202041a000000a003400039000800000003001d00000000002304350000000602100039000000000202041a000000ff002001900000000002000039000000010200c039000000c003400039000700000003001d00000000002304350000000702100039000000000202041a000000e003400039000a00000003001d00000000002304350000000801100039000000000101041a0000010003400039000009a602100197000d00000003001d0000000000230435000009af001001980000000001000039000000010100c0390000012002400039000900000002001d00000000001204350000004001400039000600000001001d00000000000104350000000601000039000000000101041a000000010110003a0000163c0000613d0000000602000039000000000012041b0000000e02000029000000000012043500000011010000290000000d020000290000000000120435000000000010043f0000001901000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000000043f000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a180220019700000001022001bf000000000021041b0000001101000029000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000602000039000000000202041a000500000002001d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000400000001001d0000000501000029000009a40010009c00000aa90000613d000000040200002900000a1601200167000200000001001d000000000301041a000000200020043f000000050000006b0000000501000029000009a401006041000500000001001d000300000003001d000000000003004b00001bcb0000c13d0000000401000029000000000101041a000000000001004b00001b810000c13d0000000501000029000000040200002900001be40000013d0000000001000416000000000001004b00001dc50000c13d0000002201000039000009030000013d0000000001000416000000000001004b00001dc50000c13d0000000e01000039000009030000013d0000000002000416000000000002004b00001dc50000c13d000000640010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d0000002401300370000000000101043b001000000001001d000009a60010009c00001dc50000213d0000004401300370000000000101043b000f00000001001d000000010010008c00001dc50000213d248e211e0000040f0000002401000039000000000201041a000009ad0220019700000011022001af000000000021041b0000000f0000006b000009c40100004100000000010060190000002502000039000000000302041a000009c303300197000000000113019f00000010011001af000000000012041b00000000010000190000248f0001042e0000000001000416000000000001004b00001dc50000c13d0000000c01000039000009030000013d0000000001000416000000000001004b00001dc50000c13d0000000401000039000000000101041a000000000001004b00000b2c0000c13d00000a1101000041000000000010043f000009bd0100004100002490000104300000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001b01000039000000200010043f00000040020000390000000001000019248e246f0000040f0000097e0000013d0000000001000416000000000001004b00001dc50000c13d0000001e01000039000009030000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000501043b000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000000201500210000000000200041a0000000103000039000000000303041a000000000005004b000007c90000613d00000000045100d9000000040040008c0000163c0000c13d001000000005001d000009a602200197000009a603300197000009b404000041000000800040043f000000840030043f0000000a0110011a001100000001001d000000a40010043f0000000001000414000009250010009c0000092501008041000000c001100210000009b5011001c7248e24840000040f000000800a00003900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000007e70000613d000000000801034f000000008908043c000000000a9a043600000000005a004b000007e30000c13d000000000006004b000007f40000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000c010000613d0000001f01400039000000600110018f00000080021001bf000f00000002001d000000400020043f000000200030008c00001dc50000413d000000800200043d000000010020008c00001dc50000213d0000000202000039000000000202041a000000000300041a000009b4040000410000000f050000290000000000450435000009a60220019700000084041001bf0000000000240435000000a401100039000000110200002900000000002104350000000001000414000009250010009c0000092501008041000000c0011002100000004002500210000000000121019f000009a602300197000009b6011001c7248e24840000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000f05700029000008240000613d000000000801034f0000000f09000029000000008a08043c0000000009a90436000000000059004b000008200000c13d000000000006004b000008310000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000014080000613d0000001f01400039000000600110018f0000000f01100029001100000001001d000000400010043f000000200030008c00001dc50000413d0000000f010000290000000001010433000000010010008c00001dc50000213d00000010040000290000000101400210000000000200041a0000000303000039000000000303041a000000000004004b000008480000613d00000000044100d9000000020040008c0000163c0000c13d000009a602200197000009a603300197000009b4040000410000001105000029000000000045043500000004045001bf00000000003404350000000a0110011a000000240350003900000000001304350000000001000414000009250010009c0000092501008041000000c0011002100000004003500210000000000131019f000009b6011001c7248e24840000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0540018f000000000a040019000000200640019000000011046000290000086a0000613d000000000701034f0000001108000029000000007907043c0000000008980436000000000048004b000008660000c13d000000000005004b000008770000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350000000100200190000016aa0000613d000000110100002900000000020a001900100000000a001d248e1e420000040f00000011010000290000001002100029248e1e620000040f00000000010000190000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d248e211e0000040f00000004010000390000000001100367000000000101043b0000002702000039000000000012041b00000000010000190000248f0001042e0000000001000416000000000001004b00001dc50000c13d000009b1010000410000097e0000013d0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001901000039000000200010043f000000400200003900000000010000190011000000030353248e246f0000040f000000110200035f0000002402200370000000000202043b000000000020043f000000200010043f00000000010000190000004002000039248e246f0000040f00000abe0000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000000000010043f0000001301000039000000200010043f00000040020000390000000001000019248e246f0000040f0000000102100039000000000302041a0000000202100039000000000402041a0000000302100039000000000502041a0000000402100039000000000602041a0000000502100039000000000702041a0000000702100039000000000902041a0000000802100039000000000b02041a000000000201041a0000000601100039000000000101041a000000ff0810018f000009a60ab00197000000a001b00270000000ff0b10018f0000008001000039248e1e0b0000040f000000800110008a000009250010009c00000925010080410000006001100210000009b8011001c70000248f0001042e0000000001000416000000000001004b00001dc50000c13d00000a0701000041000000800010043f000009b7010000410000248f0001042e0000000001000416000000000001004b00001dc50000c13d0000000a01000039000009030000013d0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000002401300370000000000401043b0000000401300370000000000301043b000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000000801000039000000000101041a000000000013004b00000bbd0000a13d000009eb01000041000000000010043f000009bd0100004100002490000104300000000001000416000000000001004b00001dc50000c13d00000025010000390000097e0000013d0000000001000416000000000001004b00001dc50000c13d0000000d01000039000000000101041a000000800010043f000009b7010000410000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d00000000030004150000000b01000039000000000201041a000000000002004b000000000100001900000bc30000c13d00000000020004150000000002230049000000000200000200000b080000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d248e211e0000040f00000004010000390000000001100367000000000101043b0000001f02000039000000000012041b00000000010000190000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f000000150100003900000afc0000013d0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d0000001101000029000000000010043f0000001a01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000d02000039000000000202041a000000000101043b000000000101041a001000000002001d000f00000001001d000000000012001a0000163c0000413d000009bf0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d0000000f030000290000001002300029000000000101043b000f00000001001d000000000012004b000000000100001900000b080000413d0000001101000029000000000010043f0000001a01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000100010002a0000163c0000413d00000010011000290000000f0110006c00000b080000813d0000163c0000013d0000000001000416000000000001004b00001dc50000c13d0000002401000039000000000101041a000009a601100197000000800010043f000009b7010000410000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000000401300370000000000101043b001100000001001d0000002401300370000000000101043b001000000001001d000000010010008c00001dc50000213d000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000009a10000c13d0000001102000029000000000002004b0000099d0000613d0000000901000039000000000101041a000000000012004b000011350000a13d000009bc01000041000000000010043f000009bd010000410000249000010430000009b202000041000000000020043f000000040010043f000009b30100004100002490000104300000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f000000100100003900000afc0000013d0000000001000416000000000001004b00001dc50000c13d000009c701000041000000800010043f000009b7010000410000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001701000039000000200010043f00000040020000390000000001000019248e246f0000040f0000000202100039000000000202041a0000000103100039000000000303041a000000000101041a000000800010043f000000a00030043f000000c00020043f000009f4010000410000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000640010008c00001dc50000413d0000004401300370000000000101043b001100000001001d000000010010008c00001dc50000213d0000000401300370000000000101043b0000002402300370000000000402043b000009b102000041000000000202041a000009a6032001970000000002000411000000000023004b00000b1e0000c13d0000000903000039000000000203041a000000010220003a0000163c0000613d000000000023041b000000e003000039000000400030043f000000800010043f001000000004001d000000a00040043f0000001101000029000000c00010043f000000000020043f0000001401000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000800200043d000000000021041b0000000102100039000000a00300043d000000000032041b0000000201100039000000000201041a00000a1802200197000000c00300043d000000000003004b000000010220c1bf000000000021041b0000000901000039000000000501041a000000400100043d00000020021000390000001103000029000000000032043500000010020000290000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009a5011001c70000800d020000390000000203000039000009b904000041000011570000013d0000000001000416000000000001004b00001dc50000c13d0000000001000411000000000010043f0000001801000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000ff0010019000000b840000c13d00000a0f01000041000000000010043f000009bd0100004100002490000104300000000001000416000000000001004b00001dc50000c13d0000000501000039000000000101041a000000ff0010019000000b4c0000c13d000000800100003900000000020000190000000000210435000009250010009c00000925010080410000004001100210000009ae011001c70000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001104000029000009a40040009c00000aa90000613d000000000004004b0000000002040019000009a40200604100000a1603100167000000000303041a000000000003004b00000eac0000c13d000000000301041a000000000023004b00000ebc0000613d0000000103100039000000000303041a000000000023004b00000ebc0000613d0000000201100039000000000101041a000000000021004b000012030000c13d00000ebc0000013d0000000002000416000000000002004b00001dc50000c13d000000440010008c00001dc50000413d0000002401300370000000000101043b001000000001001d0000000401300370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001103000029000009a40030009c00000c590000c13d000009fe01000041000000000010043f000009f70100004100002490000104300000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d248e211e0000040f000000010100003900000ad10000013d0000000001000416000000000001004b00001dc50000c13d0000000501000039000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f000009b7010000410000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d248e211e0000040f0000000201000039000000000201041a000009ad0220019700000011022001af000000000021041b00000000010000190000248f0001042e0000000001000416000000000001004b00001dc50000c13d0000000001000411248e212a0000040f0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b00000b9d0000c13d00000a0601000041000000000010043f000009bd0100004100002490000104300000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b000009a60010009c00001dc50000213d000000000010043f0000001201000039000000200010043f00000040020000390000000001000019248e246f0000040f000000000101041a000000800010043f000009b7010000410000248f0001042e0000000001000416000000000001004b00001dc50000c13d248e1e6d0000040f000000400200043d0000000000120435000009250020009c00000925020080410000004001200210000009ae011001c70000248f0001042e0000000002000416000000000002004b00001dc50000c13d000000240010008c00001dc50000413d0000000401300370000000000101043b001100000001001d000009a60010009c00001dc50000213d248e211e0000040f0000001101000029248e21030000040f00000000010000190000248f0001042e000009b201000041000000000010043f000000040020043f000009b3010000410000249000010430000009e001000041000000000010043f000009bd010000410000249000010430000009b201000041000000000010043f000000040050043f000009b3010000410000249000010430001100000001001d000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000301043b000000110130006c0000163c0000413d0000001e02000039000000000202041a000000000002004b00000cf20000613d00000000012100d9000000010110003a0000163c0000613d001000000003001d248e1e540000040f00000010030000290000001102000029000000000021001a0000163c0000413d0000000001210019000000000131004b00000b080000813d0000163c0000013d0000000401000039000000000101041a001100000001001d000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b000000110110006c0000163c0000413d0000001e02000039000000000202041a000000000002004b00000cf20000613d00000000012100d9000000ff0010008c0000163c0000213d0000001f02000039000000000202041a000000000212022f000000400100043d00000a410000013d0000000001000415000000130110008a000000050110021000000a140030009c000016ca0000813d000000010630027000000005076002100000003f0370003900000a1304300197000000400200043d0000000003240019000000000043004b00000000040000390000000104004039000009aa0030009c000016ca0000213d0000000100400190000016ca0000c13d000000400030043f0000000008620436000000000006004b00000d3f0000c13d0000000501100270000000000102001f000000400100043d001100000001001d000011690000013d0000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b001000000001001d000000000201041a0000000901000039000000000101041a001100000002001d000000000012004b0000104e0000c13d00000a0e01000041000000000010043f000009bd010000410000249000010430001100000001001d0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000001041b0000000e01000039000000000101041a000000000001004b000000110300002900000de80000613d00000a1602100129000000000032004b00000de80000813d00000a0901000041000000000010043f000009f70100004100002490000104300000000f02000039000000000012041b00000000010000190000248f0001042e000000010030008c00000c380000c13d000009ea01000041000000000010043f000009bd010000410000249000010430000d00000002001d000e00000003001d0000000401000039000000000101041a001000000001001d0000001f01000039000000000101041a000f00000001001d000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b000000100110006c0000163c0000413d0000001e02000039000000000202041a000000000002004b00000cf20000613d00000000012100d9001000000001001d000000ff0010008c0000163c0000213d0000001101000029000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d00000010030000290000000f0230024f000000000101043b000000000301041a00000000013200a9000000000003004b00000bf80000613d00000000033100d9000000000023004b000016b60000c13d0000000d011000fa0000000e03000029000009170000013d000000010030008c00000cf80000c13d000009e701000041000000000010043f000009bd0100004100002490000104300000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000c080000c13d000000000005004b00000c190000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000009250020009c00000925020080410000004002200210000000000112019f0000249000010430000000020230021000000000013200d9000000040010008c0000163c0000c13d001100000005001d001000000003001d00000000010004140000000a0320011a000000090020008c000f00000003001d000004c80000a13d000009250010009c0000092501008041000000c001100210000009a7011001c700008009020000390000000005000019248e24840000040f000e00000002001d001100000000001d000004ce0000013d000009f901000041000000000010043f000009bd010000410000249000010430001000000004001d001100000003001d000000000030043f0000001301000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b00000005011000390000001002000029000000000021041b000000400100043d0000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d020000390000000203000039000009e904000041000011560000013d00000a1602100167000000000003004b0000000004030019000009a404006041000000000202041a000000000002004b000f00000004001d000011740000c13d000000000201041a000000000042004b000011840000613d0000000102100039000000000202041a0000000f0020006c000011840000613d0000000201100039000000000101041a0000000f0010006c000011840000613d000012030000013d001100000003001d0000000001000411000009a606100198000011bb0000c13d000009de01000041000000000010043f000000040000043f000009b3010000410000249000010430000000200010043f000000000030043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b000000110400002900000c8a0000c13d000009fb01000041000000000010043f000009bd010000410000249000010430000000000040043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b001100000001001d0000000701100039000f00000001001d000000000201041a0000000001000416000000000021004b00000ce40000c13d0000002702000039000000000202041a000000640020008c0000163c0000213d00000011030000290000000803300039000e00000003001d000000000303041a000009a604300197000000000001004b000014c10000c13d0000000001000414000009250010009c0000092501008041000000c0011002100000000002040019248e24840000040f00000060031002700000092503300198000015160000c13d000000010020019000000fd20000613d0000000e01000029000000000101041a000009a601100197000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b000d00000002001d00000a1601200167000a00000001001d000000000101041a000b00000001001d000000000001004b000018040000c13d0000000d040000290000000201400039000c00000001001d000000000101041a0000000102400039000000000302041a000000000404041a000000100040006c000019b40000c13d0000000d04000029000000000034041b000019b60000013d000009f801000041000000000010043f000009bd0100004100002490000104300000000401000039000000000301041a0000000a01000039000000000401041a000000000134004b0000163c0000413d0000001e02000039000000000202041a000000000002004b000013c10000c13d00000a1001000041000000000010043f0000001201000039000000040010043f000009b3010000410000249000010430001000000004001d001100000003001d000000000030043f0000001401000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b00000001011000390000001002000029000000000021041b000000400100043d0000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d020000390000000203000039000009e604000041000011560000013d0000001f03200039000009a8033001970000003f03300039000009a903300197000000400400043d0000000003340019000000000043004b00000000050000390000000105004039000009aa0030009c000016ca0000213d0000000100500190000016ca0000c13d000000400030043f0000001f0320018f0000000005240436000009ab04200198000000000245001900000d310000613d000000000601034f000000006706043c0000000005750436000000000025004b00000d2d0000c13d000000000003004b000004d10000613d000000000141034f0000000303300210000000000402043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000120435000004d10000013d0000000003000019000000400400043d000009c20040009c000016ca0000213d0000014005400039000000400050043f0000012005400039000000000005043500000100054000390000000000050435000000e0054000390000000000050435000000c0054000390000000000050435000000a0054000390000000000050435000000800540003900000000000504350000006005400039000000000005043500000040054000390000000000050435000000200540003900000000000504350000000000040435000000000538001900000000004504350000002003300039000000000073004b00000d400000413d000d00000008001d000f00000006001d0000000501100270000000000102001f001100000000001d000e00000002001d000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001101100029000000000101041a001000000001001d000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f0000001004000029000009a40040009c0000000004006019000000010020019000001dc50000613d000000000201043b00000a1601200167000000000101041a000000000001004b00000d8b0000613d000000010110027000000d990000013d000000000102041a000000000001004b0000000001000039000000010100c03900000d990000613d0000000103200039000000000303041a000000000003004b00000d990000613d0000000201200039000000000101041a000000000001004b00000003010000390000000201006039000000110010006b0000153c0000813d000000000040043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400600043d000009c20060009c0000000f050000290000000e020000290000000d07000029000016ca0000213d000000000101043b0000014003600039000000400030043f000000000301041a00000000033604360000000104100039000000000404041a00000000004304350000000203100039000000000303041a000000400460003900000000003404350000000303100039000000000303041a000000600460003900000000003404350000000403100039000000000303041a000000800460003900000000003404350000000503100039000000000303041a000000a00460003900000000003404350000000603100039000000000303041a000000ff003001900000000003000039000000010300c039000000c00460003900000000003404350000000703100039000000000303041a000000e00460003900000000003404350000000801100039000000000101041a0000010003600039000009a60410019700000000004304350000012003600039000009af001001980000000001000039000000010100c039000000000013043500000000010204330000001103000029000000000031004b0000148c0000a13d0000000501300210000000000117001900000000006104350000000001020433000000000031004b0000148c0000a13d001100010030003d000000110050006b00000d630000413d00000b810000013d00000000013100a9001009c700100132000000100230006c0000163c0000413d0000000001000411248e21fe0000040f0000000001000411000000000010043f0000001b01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000009a601100198000014960000c13d00000000010004100000001002000029248e21fe0000040f0000000001000410000000000010043f0000001d01000039000000200010043f00000000010004140000149e0000013d000000200010043f000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b0000001104000029000012030000613d000000000040043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000f00000001001d0000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000e00000001001d0000000101100039000000000101041a000000100010006b000014880000813d0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001002000029000000000020043f000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000ff00100190000014880000c13d0000000f010000290000000801100039000000000101041a000009af00100198000014360000613d0000000f010000290000000201100039000000000201041a000000640020008c000014bd0000c13d0000000f020000290000000602200039000000000202041a000000ff00200190000014920000c13d0000001002000029000000000021041b0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001002000029000000000020043f000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a180220019700000001022001bf000000000021041b0000000e010000290000000201100039000000000201041a000000010220003a0000163c0000613d000000000021041b000000400100043d00000010020000290000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d020000390000000303000039000009cc0400004100000000050004110000001106000029248e24840000040f000000010020019000001dc50000613d0000000f030000290000000401300039000000000201041a0000000301300039000000000101041a248e1e540000040f00000000020100190000000001000411248e23240000040f00000000010000190000248f0001042e000000200010043f000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b0000001104000029000012030000613d000000000040043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b001000000001001d0000000801100039000000000101041a000009af00100198000014360000613d00000010010000290000000401100039000f00000001001d000000000101041a000000010210003a0000163c0000613d0000000f03000029000000000023041b000000050010008c000015400000413d000009f301000041000000000010043f000009bd010000410000249000010430000009a40200004100000a1603100167000000000303041a000000000003004b00000eed0000c13d000000000301041a000000000023004b00000efd0000613d0000000103100039000000000303041a000000000023004b00000efd0000613d0000000201100039000000000101041a000000000021004b000012030000c13d00000efd0000013d000000200010043f000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b0000001104000029000012030000613d000000000040043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b001000000001001d0000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000f00000001001d00000010010000290000000801100039000000000101041a000009af00100198000014360000613d00000010010000290000000201100039000d00000001001d000000000101041a000e00000001001d000000640010008c000016350000613d00000010010000290000000601100039000000000101041a000000ff00100190000014920000c13d0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000e02000029000000000020043f000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a1802200197000000000021041b00000064010000390000000d02000029000000000012041b0000000f010000290000000201100039000000000201041a000000000002004b0000163c0000613d000000010220008a000000000021041b0000000001000414000009250010009c0000092501008041000000c001100210000009a7011001c70000800d02000039000000030300003900000a010400004100000000050004110000001106000029248e24840000040f000000010020019000001dc50000613d00000010020000290000000401200039000000000101041a0000000302200039000000000202041a00110000002100ad000000000002004b00000f6b0000613d00000011022000f9000000000012004b0000163c0000c13d0000000001000411248e212a0000040f0000000b01000039000000000201041a000000110220006c0000163c0000413d000000000021041b0000000001000411000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000110220006c0000163c0000413d000000000021041b0000000001000411000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a001100000001001d0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000011010000290000000000120435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009a5011001c70000800d02000039000000020300003900000a0204000041000014bb0000013d000009a7011001c700008009020000390000000f030000290000000005000019248e24840000040f001100000002001d0000006002100270000009250220019800000fd60000c13d0000000301000039000000000101041a000009a6041001970000001001000029000000000001004b000012760000c13d0000000001000414000009250010009c0000092501008041000000c0011002100000000002040019248e24840000040f00000060031002700000092503300198000012850000c13d00000011030000290000000e0130017f000000000121016f00000001001001900000115a0000c13d000009fd01000041000000000010043f000009bd0100004100002490000104300000001f03200039000009a8033001970000003f03300039000009a903300197000000400400043d0000000003340019000000000043004b00000000050000390000000105004039000009aa0030009c000016ca0000213d0000000100500190000016ca0000c13d000000400030043f0000001f0320018f0000000005240436000009ab04200198000000000245001900000fee0000613d000000000601034f000000006706043c0000000005750436000000000025004b00000fea0000c13d000000000003004b00000fbe0000613d000000000141034f0000000303300210000000000402043300000000043401cf000000000434022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f000000000012043500000fbe0000013d000000000020043f0000001301000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000801100039000000000201041a000009c8022001970000001004000029000000000004004b000009c4030000410000000003006019000000000232019f000000000021041b000000400100043d0000000000410435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d020000390000000203000039000009c904000041000011560000013d000000200010043f000000000030043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b000012030000613d000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b00000a1602100167000000000202041a000000000002004b000014140000c13d000000000201041a000000100020006c000014240000613d0000000102100039000000000202041a000000100020006c000014240000613d0000000201100039000000000101041a000000100010006c00000c860000c13d000014240000013d0000000001000411000000000010043f0000001a01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000f00000001001d000009bf0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b0000000f0110006c0000163c0000413d0000000d02000039000000000202041a000000000021004b000016390000813d00000a0d01000041000000000010043f000009bd01000041000024900001043000000001022002700000000d0520006c0000115c0000a13d000000110050006c0000001105008029000009aa0050009c000016ca0000213d00000005015002100000003f0210003900000a1302200197000000400400043d0000000002240019000000000042004b00000000030000390000000103004039000009aa0020009c000016ca0000213d0000000100300190000016ca0000c13d000000400020043f000c00000004001d0000000002540436000b00000002001d000a00000005001d000000000005004b000011630000613d00000000020000190000000b05000029000000400300043d000009c20030009c000016ca0000213d0000014004300039000000400040043f0000012004300039000000000004043500000100043000390000000000040435000000e0043000390000000000040435000000c0043000390000000000040435000000a0043000390000000000040435000000800430003900000000000404350000006004300039000000000004043500000040043000390000000000040435000000200430003900000000000404350000000000030435000000000425001900000000003404350000002002200039000000000012004b000010900000413d001100000000001d000009a201000041000000040010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000001103000029000e000d0030002d000000000101043b0000000e01100029000000000101041a000f00000001001d000009a201000041000000040010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f0000000f04000029000009a40040009c0000000004006019000000010020019000001dc50000613d000000000201043b00000a1601200167000000000101041a000000000001004b000010d80000613d0000000101100270000010e60000013d000000000102041a000000000001004b0000000001000039000000010100c039000010e60000613d0000000103200039000000000303041a000000000003004b000010e60000613d0000000201200039000000000101041a000000000001004b000000030100003900000002010060390000000e0010006b0000153c0000813d000000000040043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400200043d000009c20020009c0000000c050000290000000a060000290000000b07000029000016ca0000213d000000000101043b0000014003200039000000400030043f000000000301041a00000000033204360000000104100039000000000404041a00000000004304350000000203100039000000000303041a000000400420003900000000003404350000000303100039000000000303041a000000600420003900000000003404350000000403100039000000000303041a000000800420003900000000003404350000000503100039000000000303041a000000a00420003900000000003404350000000603100039000000000303041a000000ff003001900000000003000039000000010300c039000000c00420003900000000003404350000000703100039000000000303041a000000e00420003900000000003404350000000801100039000000000101041a0000010003200039000009a60410019700000000004304350000012003200039000009af001001980000000001000039000000010100c039000000000013043500000000010504330000001103000029000000000031004b0000148c0000a13d0000000501300210000000000117001900000000002104350000000001050433000000000031004b0000148c0000a13d001100010030003d000000110060006b000010ae0000413d000011630000013d000000000020043f0000001401000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000201100039000000000201041a00000a18022001970000001003000029000000000232019f000000000021041b000000400100043d0000000000310435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d020000390000000203000039000009bb040000410000001105000029248e24840000040f000000010020019000001dc50000613d00000000010000190000248f0001042e000000400200043d00000a120020009c000016ca0000213d0000002001200039000000400010043f000c00000002001d0000000000020435000000000100041500000009011000690000000001000002000000400100043d001100000001001d0000000c02000029248e1dc70000040f00000011020000290000000001210049000009250010009c00000925010080410000006001100210000009250020009c00000925020080410000004002200210000000000121019f0000248f0001042e000000200010043f000000000040043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b0000001103000029000012030000613d000000000030043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000802100039000000000202041a000009af00200198000014360000613d0000000602100039000000000302041a000000ff00300190000014920000c13d00000001033001bf000000000032041b00000007011000390000001002000029000000000021041b000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b00000a1601200167000d00000001001d000000000101041a001000000002001d000000200020043f000e00000001001d000000000001004b00001a190000c13d0000001001000029000000000101041a000000000001004b000016dc0000c13d0000000f01000029000000100200002900001a320000013d000009b101000041000000000201041a000009ad03200197000000000363019f000000000031041b0000000001000414000009a605200197000009250010009c0000092501008041000000c001100210000009a7011001c70000800d020000390000000303000039000009d604000041248e24840000040f000000010020019000001dc50000613d000009d7010000410000000d02000039000000000012041b000009d8010000410000000e02000039000000000012041b000009d9010000410000000f02000039000000000012041b00000014010000390000002702000039000000000012041b000009da010000410000001e02000039000000000012041b000009db010000410000001f02000039000000000012041b000000110000006b0000115a0000c13d000009cf01000041000000000201041a000009dc02200197000000000021041b0000000103000039000000400100043d0000000000310435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d02000039000009dd04000041000011570000013d000000200010043f000000000040043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b0000001103000029000012070000c13d000009ff01000041000000000010043f000009bd010000410000249000010430000000000030043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400200043d000f00000002001d000009c20020009c000016ca0000213d000000000101043b0000000f050000290000014002500039000000400020043f000000000201041a00000000022504360000000103100039000000000303041a00000000003204350000000202100039000000000202041a0000004003500039000e00000003001d00000000002304350000000303100039000000000303041a000000600450003900000000003404350000000403100039000000000303041a000000800450003900000000003404350000000503100039000000000303041a000000a00450003900000000003404350000000603100039000000000303041a000000ff003001900000000003000039000000010300c039000000c00450003900000000003404350000000703100039000000000303041a000000e00450003900000000003404350000000801100039000000000101041a0000010003500039000009a60410019700000000004304350000012003500039000009af001001980000000001000039000000010100c0390000000000130435000000640020008c000014bd0000c13d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b000d00000002001d00000a1601200167000a00000001001d000000000101041a000b00000001001d000000000001004b000016e60000c13d0000000d040000290000000201400039000c00000001001d000000000101041a0000000102400039000000000302041a000000000404041a000000100040006c000018350000c13d0000000d04000029000000000034041b000018370000013d000000010210021000000000011200d9000000020010008c0000163c0000c13d0000000001000414000000090020008c00000fc50000a13d0000000a0320011a000009250010009c0000092501008041000000c001100210000009a7011001c70000800902000039000000000500001900000fc90000013d0000001f04300039000009a8044001970000003f04400039000009a904400197000000400500043d0000000004450019000000000054004b00000000060000390000000106004039000009aa0040009c000016ca0000213d0000000100600190000016ca0000c13d000000400040043f0000001f0430018f0000000006350436000009ab0530019800000000035600190000129d0000613d000000000701034f000000007807043c0000000006860436000000000036004b000012990000c13d000000000004004b00000fcd0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000fcd0000013d000000000010043f0000001801000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a180220019700000001022001bf000000000021041b000000110000006b000014d10000c13d0000000101000039000000000010043f0000001401000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400200043d001100000002001d000009be0020009c000016ca0000213d000000000101043b00000011040000290000006002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a000000000032043500000040024000390000000201100039000000000101041a000000ff001001900000000001000039000000010100c03900000000001204350000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b0000000101000039000000000012041b00000011010000290000000001010433001100000002001d0000000102200039000000000012041b0000000001000411000000000010043f0000001a01000039000000200010043f000009bf0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b001000000001001d0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001002000029000000000021041b000000400100043d001000000001001d0000000001000414000009250010009c0000092501008041000000c001100210000009a7011001c70000800d020000390000000203000039000009c1040000410000000005000411248e24840000040f000000010020019000001dc50000613d0000000101000039000000000010043f0000001301000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000001002000029000009c20020009c000016ca0000213d000000000101043b00000010040000290000014002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000f00000003001d00000000002304350000000302100039000000000202041a0000006003400039000d00000003001d00000000002304350000000402100039000000000202041a0000008003400039000c00000003001d00000000002304350000000502100039000000000202041a000000a003400039000900000003001d00000000002304350000000602100039000000000202041a000000ff002001900000000002000039000000010200c039000000c003400039000800000003001d00000000002304350000000702100039000000000202041a000000e003400039000b00000003001d00000000002304350000000801100039000000000101041a0000010003400039000009a602100197000e00000003001d0000000000230435000009af001001980000000001000039000000010100c0390000012002400039000a00000002001d00000000001204350000004001400039000700000001001d00000000000104350000000601000039000000000101041a000000010110003a0000163c0000613d0000000602000039000000000012041b0000000f02000029000000000012043500000000010004110000000e020000290000000000120435000000000010043f0000001901000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000000043f000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a180220019700000001022001bf000000000021041b0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000602000039000000000202041a000600000002001d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000500000001001d0000000601000029000009a40010009c00000aa90000613d000000050200002900000a1601200167000300000001001d000000000301041a000000200020043f000000060000006b0000000601000029000009a401006041000600000001001d000400000003001d000000000003004b00001ca50000c13d0000000501000029000000000101041a000000000001004b00001b8b0000c13d0000000601000029000000050200002900001cbe0000013d00000000012100d9000000ff0010008c0000163c0000213d001000000004001d000c00000002001d000d00000003001d0000001f02000039000000000202041a000f0000001202370000000c01000039000000000101041a001100000001001d000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b0000001006000029000000000016004b00000011070000290000000d040000290000000c05000029000016680000813d000000000246004b0000000f080000290000163c0000413d00000000025200d9000000010320003a0000163c0000613d00000000025300a900000000033200d9000000000053004b0000163c0000c13d000000000042001a0000163c0000413d0000000003420019000000000013004b00000000020100190000000002034019000000000462004b0000163c0000413d000000000008004b000013fe0000613d00000000054800a900000000068500d9000000000046004b0000163c0000c13d000000000005004b000013fe0000613d000009c7045000d100000000055400d9000009c70050009c000013ff0000613d0000163c0000013d00000000040000190000000e044000fa000000000047001a0000163c0000413d001100000047001d000000000013004b000000010880a270000f00000008001d001000000002001d000013cd0000013d0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000140f0000c13d00000c0c0000013d000000200010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000000001004b00000c860000613d0000001101000029000000000010043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000802100039000000000202041a000009af00200198000016310000c13d00000a0401000041000000000010043f000009bd0100004100002490000104300000000f010000290000000001010433248e1f130000040f000000000200041a000000400500043d000600000005001d000009ec030000410000000000350435000000040350003900000000040004110000000000430435000009250050009c000009250300004100000000030540190000004003300210000500000001001d0000000001000414000009250010009c0000092501008041000000c001100210000000000131019f000009b3011001c7000009a602200197000400000002001d248e24890000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000060b0000290000000605700029000014630000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000145f0000c13d000000000006004b000014700000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f000000000065043500000001002001900000150a0000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000300000002001d000009aa0020009c000016ca0000213d0000000100100190000016ca0000c13d0000000301000029000000400010043f000000200030008c00001dc50000413d00000000010b0433000000050010006c000017170000813d00000a0b01000041000000000010043f000009bd010000410000249000010430000009ca01000041000000000010043f000009bd01000041000024900001043000000a1001000041000000000010043f0000003201000039000000040010043f000009b301000041000024900001043000000a0001000041000000000010043f000009bd010000410000249000010430000f00000001001d0000001002000029248e21fe0000040f0000000f01000029000000000010043f0000001d01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000100020002a0000163c0000413d0000001002200029000000000021041b000000400100043d00000011020000290000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d02000039000000020300003900000a05040000410000000005000411000011570000013d000009cb01000041000000000010043f000009bd010000410000249000010430000000640320008900000000023100a900000000011200d9000000000031004b0000163c0000c13d0000000001000414000000630020008c00000caa0000a13d000000640320011a000009250010009c0000092501008041000000c001100210000009a7011001c70000800902000039000000000500001900000cae0000013d0000000001000411000000000010043f0000001b01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000009ad022001970000001103000029000000000232019f000000000021041b000000000030043f0000001c01000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a001100000002001d000009aa0020009c000016ca0000213d00000011020000290000000102200039000000000021041b000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009ba011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001101100029000000000201041a000009ad022001970000000003000411000000000232019f000000000021041b000012be0000013d0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000015110000c13d00000c0c0000013d0000001f04300039000009a8044001970000003f04400039000009a904400197000000400500043d0000000004450019000000000054004b00000000060000390000000106004039000009aa0040009c000016ca0000213d0000000100600190000016ca0000c13d000000400040043f0000001f0430018f0000000006350436000009ab0530019800000000035600190000152e0000613d000000000701034f000000007807043c0000000006860436000000000036004b0000152a0000c13d000000000004004b00000cb20000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000cb20000013d00000a1501000041000000000010043f000009bd0100004100002490000104300000002501000039000000000101041a000009af00100198000001ab0000613d00000010010000290000000501100039000000000101041a248e1f130000040f000000000200041a000000400500043d000e00000005001d000009ec030000410000000000350435000000040350003900000000040004110000000000430435000009250050009c000009250300004100000000030540190000004003300210000d00000001001d0000000001000414000009250010009c0000092501008041000000c001100210000000000131019f000009b3011001c7000009a602200197000c00000002001d248e24890000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000e0b0000290000000e057000290000156e0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000156a0000c13d000000000006004b0000157b0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000016d00000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000b00000002001d000009aa0020009c000016ca0000213d0000000100100190000016ca0000c13d0000000b01000029000000400010043f000000200030008c00001dc50000413d00000000010b04330000000d0010006c000014840000413d0000000b0300002900000044013000390000000d0200002900000000002104350000000001000410000009a60110019700000024023000390000000000120435000009ed0100004100000000001304350000000001000411000009a60110019700000004023000390000000000120435000009250030009c0000092501000041000000000103401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ee011001c70000000c02000029248e24840000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000b05700029000015b80000613d000000000801034f0000000b09000029000000008a08043c0000000009a90436000000000059004b000015b40000c13d000000000006004b000015c50000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001a4e0000613d0000001f01400039000000600210018f0000000b01200029000000000021004b00000000020000390000000102004039000009aa0010009c000016ca0000213d0000000100200190000016ca0000c13d000000400010043f000000200030008c00001dc50000413d0000000b010000290000000001010433000000010010008c00001dc50000213d000000000100041a0000000f02000039000000000202041a000e00000002001d000000000002004b000015e20000613d000000010200008a0000000e022000fa0000000d0020006c00000bb50000413d000009a602100197000009d1010000410000000000100443000c00000002001d00000004002004430000000001000414000009250010009c0000092501008041000000c001100210000009d2011001c70000800202000039248e24890000040f0000000100200190000019a30000613d000000000101043b000000000001004b00001dc50000613d0000000e020000290000000d012000b9000009c70110012a000000400300043d000009ef020000410000000002230436000b00000002001d00000004023000390000000000120435000009250030009c000e00000003001d00000925010000410000000001034019000d0040001002180000000001000414000009250010009c0000092501008041000000c0011002100000000d011001af000009b3011001c70000000c02000029248e24840000040f000000010020019000001b740000613d0000000e01000029000009aa0010009c000016ca0000213d0000000e03000029000000400030043f0000001001000029000000000601041a0000000201100039000000000501041a0000000f01000029000000000101041a00000011020000290000000b04000029000000000024043500000000001304350000004001300039001100000005001d00000000005104350000000001000414000009250010009c0000092501008041000000c0011002100000000d011001af000009c5011001c70000800d020000390000000303000039000009f2040000410000000005000411248e24840000040f000000010020019000001dc50000613d0000001101000029000000640010008c0000115a0000613d00000010010000290000000301100039000000000201041a00000ea80000013d0000000602100039000000000302041a000000ff00300190000016420000c13d00000a0301000041000000000010043f000009bd0100004100002490000104300000001101000029000000010110003a000016ba0000c13d00000a1001000041000000000010043f0000001101000039000000040010043f000009b301000041000024900001043000000a1803300197000000000032041b0000000701100039000000000001041b000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b000f00000002001d00000a1601200167000c00000001001d000000000101041a000d00000001001d000000000001004b000017d40000c13d0000000f040000290000000201400039000e00000001001d000000000101041a0000000102400039000000000302041a000000000404041a000000100040006c000019b00000c13d0000000f04000029000000000034041b000000000012041b00001a3e0000013d0000000b01000029000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a001000000001001d0000000b01000029000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000f00000001001d0000000b01000029000000000010043f0000001201000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000101041a000000110210006b0000163c0000413d0000000f012000b90000000f0000006b0000169f0000613d0000000f031000fa000000000023004b0000163c0000c13d000009c70110012a000000100010002a0000163c0000413d0000000e02000039000000000202041a000009c70020009c0000163c0000213d0000001001100029000009c702200099000001280000c13d0000012b0000013d0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000016b10000c13d00000c0c0000013d000009f601000041000000000010043f000009f7010000410000249000010430000000000010043f0000001401000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000400200043d001100000002001d000009be0020009c000018910000a13d00000a1001000041000000000010043f0000004101000039000000040010043f000009b30100004100002490000104300000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000016d70000c13d00000c0c0000013d0000000f0010006c00001a330000613d00000010020000290000000102200039000000000302041a000e00000003001d000000000003004b000019e30000c13d0000000f0100002900001a320000013d0000000d01000029000000200010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000c00000001001d000000000101041a001000000001001d000000000001004b0000183a0000613d0000000b010000290000000101100270000b000100100092000000100010006b000017120000613d00000010010000290000000d011000290000000b030000290000000d02300029000000000202041a000000010110008a000000000021041b000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001002000029000000000021041b0000000b01000029000000010110021000000001011001bf0000000a02000029000018370000013d00000003030000290000004401300039000000050200002900000000002104350000000001000410000009a60110019700000024023000390000000000120435000009ed0100004100000000001304350000000001000411000009a60110019700000004023000390000000000120435000009250030009c0000092501000041000000000103401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ee011001c70000000402000029248e24840000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000305700029000017400000613d000000000801034f0000000309000029000000008a08043c0000000009a90436000000000059004b0000173c0000c13d000000000006004b0000174d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000019a40000613d0000001f01400039000000600210018f0000000301200029000000000021004b00000000020000390000000102004039000009aa0010009c000016ca0000213d0000000100200190000016ca0000c13d000000400010043f000000200030008c00001dc50000413d00000003010000290000000001010433000000010010008c00001dc50000213d000000000100041a0000000f02000039000000000202041a000600000002001d000000000002004b0000176a0000613d000000010200008a00000006022000fa000000050020006c00000bb50000413d000009a602100197000009d1010000410000000000100443000400000002001d00000004002004430000000001000414000009250010009c0000092501008041000000c001100210000009d2011001c70000800202000039248e24890000040f0000000100200190000019a30000613d000000000101043b000000000001004b00001dc50000613d000000060200002900000005012000b9000009c70110012a000000400300043d000009ef02000041000000000023043500000004023000390000000000120435000009250030009c000600000003001d0000092501000041000000000103401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009b3011001c70000000402000029248e24840000040f000000010020019000001b4c0000613d0000000601000029000009aa0010009c000016ca0000213d0000000601000029000000400010043f00000064020000390000000e0100002900000000002104350000000601000039000000000101041a000400000001001d000600010010003e0000163c0000613d00000006010000390000000602000029000000000021041b0000000d01000029000000000021043500000000010004110000000c020000290000000000120435000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000300000001001d0000000401000029000009f00010009c00000aa90000613d000000030200002900000a1601200167000200000001001d000000000101041a000000200020043f000400000001001d000000000001004b00001d540000c13d0000000301000029000000000101041a000000000001004b00001c5c0000c13d0000000601000029000000030200002900001d6d0000013d0000000f01000029000000200010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000e00000001001d000000000101041a001000000001001d000000000001004b00001a400000613d0000000d010000290000000101100270000000100010006b000017fe0000613d0000000f02000029000000010220008a00000010032000290000000001120019000000000101041a000000000013041b000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001002000029000000000021041b0000000d0100002900000001011001bf000000020110008a0000000c02000029000000000012041b00001a3e0000013d0000000d01000029000000200010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000c00000001001d000000000101041a000900000001001d000000000001004b000019b90000613d0000000b010000290000000101100270000b000100100092000000090010006b000018300000613d00000009010000290000000d011000290000000b030000290000000d02300029000000000202041a000000010110008a000000000021041b000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000902000029000000000021041b0000000b01000029000000010110021000000001011001bf0000000a02000029000019b60000013d000000100030006c00001a350000c13d000000000012041b0000000c01000029000000000001041b0000001101000029000000000010043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000702100039000000000002041b0000000801100039000000000001041b0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000e020000290000000002020433000000000020043f000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a00000a1802200197000000000021041b0000000f0100002900000000060104330000000e010000290000000001010433000000400200043d000000400320003900000000001304350000002001200039000000110300002900000000003104350000000000020435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009c5011001c70000800d020000390000000303000039000009ce040000410000000005000411000011570000013d000000000201043b00000011040000290000006001400039000000400010043f000000000102041a00000000031404360000000101200039000000000101041a000000000013043500000040034000390000000202200039000000000202041a000000ff002001900000000002000039000000010200c039000000000023043500001a380000613d0000002502000039000000000202041a000009af00200198000001ab0000613d248e1f130000040f000000000200041a000000400500043d000f00000005001d000009ec030000410000000000350435000000040350003900000000040004110000000000430435000009250050009c000009250300004100000000030540190000004003300210000e00000001001d0000000001000414000009250010009c0000092501008041000000c001100210000000000131019f000009b3011001c7000009a602200197000d00000002001d248e24890000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000f0b0000290000000f05700029000018cd0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000018c90000c13d000000000006004b000018da0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001a5a0000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000c00000002001d000009aa0020009c000016ca0000213d0000000100100190000016ca0000c13d0000000c01000029000000400010043f000000200030008c00001dc50000413d00000000010b04330000000e0010006c000014840000413d0000000c0300002900000044013000390000000e0200002900000000002104350000000001000410000009a60110019700000024023000390000000000120435000009ed0100004100000000001304350000000001000411000009a60110019700000004023000390000000000120435000009250030009c0000092501000041000000000103401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ee011001c70000000d02000029248e24840000040f00000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c05700029000019170000613d000000000801034f0000000c09000029000000008a08043c0000000009a90436000000000059004b000019130000c13d000000000006004b000019240000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001b680000613d0000001f01400039000000600110018f0000000c01100029000009aa0010009c000016ca0000213d000000400010043f000000200030008c00001dc50000413d0000000c010000290000000001010433000000010010008c00001dc50000213d000000000100041a0000000f02000039000000000202041a000f00000002001d000000000002004b0000193c0000613d000000010200008a0000000f022000fa0000000e0020006c00000bb50000413d000009a602100197000009d1010000410000000000100443000d00000002001d00000004002004430000000001000414000009250010009c0000092501008041000000c001100210000009d2011001c70000800202000039248e24890000040f0000000100200190000019a30000613d000000000101043b000000000001004b00001dc50000613d0000000f020000290000000e012000b9000009c70110012a000000400300043d000009ef02000041000000000023043500000004023000390000000000120435000009250030009c000f00000003001d0000092501000041000000000103401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009b3011001c70000000d02000029248e24840000040f000000010020019000001c4f0000613d0000000f01000029000009aa0010009c000016ca0000213d0000000f01000029000000400010043f0000001001000029000000000101041a000000010110003a0000163c0000613d0000001002000029000000000012041b000000010120003900000011020000290000000002020433000000000021041b0000000001000411000000000010043f0000001a01000039000000200010043f000009bf0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000019a30000613d000000000101043b001100000001001d0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001102000029000000000021041b0000001001000029000000000601041a000000400100043d0000000e020000290000000000210435000009250010009c000009250100804100000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d02000039000000030300003900000a0a040000410000000005000411000011570000013d000000000001042f0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000019ab0000c13d00000c0c0000013d000000100030006c00001a3c0000c13d000000000012041b00001a3e0000013d000000100030006c00001a4b0000c13d000000000012041b0000000c01000029000000000001041b0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000009a202000041000000040020043f000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b00000a1601200167000b00000001001d000000000101041a000d00000002001d000000200020043f000c00000001001d000000000001004b00001aa60000c13d0000000d01000029000000000101041a000000000001004b00001a660000c13d00000010010000290000000d0200002900001abf0000013d0000000e030000290000000f0030006c00001a330000613d00000010020000290000000202200039000000000302041a000c00000003001d000000000003004b000016e40000613d0000000c030000290000000f0030006c00001a330000613d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000102000039000000000021041b0000000e01000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000202000039000000000021041b0000000c01000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000302000039000000000021041b000e00070000003d0000000f01000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000000002004b00001a330000c13d0000000e02000029000000010220027000000010032000290000000f04000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000d02000029000000000012041b000000000100041400001a410000013d000000100010006c000018380000613d0000183a0000013d00000a0801000041000000000010043f000009bd010000410000249000010430000000100010006c00001a400000c13d0000000e01000029000000000001041b0000000001000414000009250010009c0000092501008041000000c001100210000009a7011001c70000800d020000390000000303000039000009b00400004100000000050004110000001106000029000011570000013d000000100010006c000019b70000613d000019b90000013d0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a550000c13d00000c0c0000013d0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001a610000c13d00000c0c0000013d000000100010006c00001ac00000613d0000000d020000290000000102200039000000000302041a000c00000003001d000000000003004b00001a700000c13d000000100100002900001abf0000013d0000000c03000029000000100030006c00001ac00000613d0000000d020000290000000202200039000000000302041a000a00000003001d000000000003004b00001a6e0000613d0000000a03000029000000100030006c00001ac00000613d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000102000039000000000021041b0000000c01000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000202000039000000000021041b0000000a01000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000302000039000000000021041b000c00070000003d0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000000002004b00001ac00000c13d0000000c0200002900000001022002700000000d032000290000001004000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000b02000029000000000012041b000009a201000041000000040010043f0000002601000039000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a3011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000201043b000d00000002001d00000a1601200167000a00000001001d000000000101041a000b00000001001d000000000001004b00001ae20000c13d0000000d040000290000000201400039000c00000001001d000000000101041a0000000102400039000000000302041a000000000404041a000000100040006c00001b140000c13d0000000d04000029000000000034041b000000000012041b00001b1a0000013d0000000d01000029000000200010043f0000001001000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000c00000001001d000000000101041a001000000001001d000000000001004b00001b1c0000613d0000000b010000290000000101100270000b000100100092000000100010006b00001b0e0000613d00000010010000290000000d011000290000000b030000290000000d02300029000000000202041a000000010110008a000000000021041b000000000020043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000001002000029000000000021041b0000000b01000029000000010110021000000001011001bf0000000a02000029000000000012041b00001b1a0000013d000000100030006c00001b180000c13d000000000012041b00001b1a0000013d000000100010006c00001b1c0000c13d0000000c01000029000000000001041b0000001101000029000000000701041a0000000e01000029000000000201041a0000000601000039000000000101041a0000000f03000029000000000303041a000000400400043d000000200540003900000000003504350000000000140435000009250040009c000009250400804100000040014002100000000003000414000009250030009c0000092503008041000000c003300210000000000113019f000009a5011001c7000009a6052001970000800d020000390000000403000039000009ac040000410000000006000411248e24840000040f000000010020019000001dc50000613d00000011040000290000000601400039000000000201041a00000a1802200197000000000021041b0000000f01000029000000000001041b00000002014000390000006402000039000000000021041b0000000001000411000009a6011001970000000e03000029000000000203041a000009ad02200197000000000112019f000000000013041b00000000010000190000248f0001042e00000060061002700000001f0460018f000009ab05600198000000400200043d000000000352001900001b580000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00001b540000c13d0000092506600197000000000004004b00001b660000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000000600160021000000c1a0000013d0000001f0530018f000009ab06300198000000400200043d000000000462001900000c0c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001b6f0000c13d00000c0c0000013d00000060061002700000001f0460018f000009ab05600198000000400200043d000000000352001900001b580000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00001b7c0000c13d00001b580000013d000000050010006c00001be50000613d00000004020000290000000102200039000000000302041a000300000003001d000000000003004b00001b950000c13d000000050100002900001be40000013d000000060010006c00001cbf0000613d00000005020000290000000102200039000000000302041a000400000003001d000000000003004b00001c6f0000c13d000000060100002900001cbe0000013d0000000303000029000000050030006c00001be50000613d00000004020000290000000202200039000000000302041a000100000003001d000000000003004b00001b890000613d0000000103000029000000050030006c00001be50000613d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000102000039000000000021041b0000000301000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000202000039000000000021041b0000000101000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000302000039000000000021041b000300070000003d0000000501000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000000002004b00001be50000c13d0000000302000029000000010220027000000004032000290000000504000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000202000029000000000012041b0000000601000039000000000101041a000000000010043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000f020000290000000002020433000000000101043b000000000021041b0000000e0200002900000000020204330000000103100039000000000023041b000000060200002900000000020204330000000203100039000000000023041b0000000c0200002900000000020204330000000303100039000000000023041b0000000b0200002900000000020204330000000403100039000000000023041b000000080200002900000000020204330000000503100039000000000023041b0000000602100039000000000302041a00000a180330019700000007040000290000000004040433000000000004004b000000010330c1bf000000000032041b0000000a0200002900000000020204330000000703100039000000000023041b00000008011000390000000d020000290000000002020433000009a602200197000000000301041a000009c303300197000000000223019f00000009030000290000000003030433000000000003004b000009c4030000410000000003006019000000000232019f000000000021041b00000010010000290000000201100039000000000201041a000000010220003a0000163c0000613d000000000021041b0000000701000039000000000201041a000000010220003a0000163c0000613d000000000021041b0000000601000039000000000101041a000000400200043d00000020032000390000000000130435000000400120003900000000000104350000000000020435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009c5011001c70000800d0200003900000003030000390000000106000039000009c6040000410000001105000029248e24840000040f000000010020019000001dc50000613d0000000c0100002900000000020104330000001101000029248e23240000040f00000000010000190000248f0001042e00000060061002700000001f0460018f000009ab05600198000000400200043d000000000352001900001b580000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00001c570000c13d00001b580000013d000000060010006c00001d6e0000613d00000003020000290000000102200039000000000302041a000400000003001d000000000003004b00001c6d0000613d0000000403000029000000060030006c00001d6e0000613d00000003020000290000000202200039000000000302041a000100000003001d000000000003004b00001d270000c13d000000060100002900001d6d0000013d0000000403000029000000060030006c00001cbf0000613d00000005020000290000000202200039000000000302041a000200000003001d000000000003004b00001b930000613d0000000203000029000000060030006c00001cbf0000613d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000102000039000000000021041b0000000401000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000202000039000000000021041b0000000201000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000302000039000000000021041b000400070000003d0000000601000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000000002004b00001cbf0000c13d0000000402000029000000010220027000000005032000290000000604000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000302000029000000000012041b0000000601000039000000000101041a000000000010043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d00000010020000290000000002020433000000000101043b000000000021041b0000000f0200002900000000020204330000000103100039000000000023041b000000070200002900000000020204330000000203100039000000000023041b0000000d0200002900000000020204330000000303100039000000000023041b0000000c0200002900000000020204330000000403100039000000000023041b000000090200002900000000020204330000000503100039000000000023041b0000000602100039000000000302041a00000a180330019700000008040000290000000004040433000000000004004b000000010330c1bf000000000032041b0000000b0200002900000000020204330000000703100039000000000023041b00000008011000390000000e020000290000000002020433000009a602200197000000000301041a000009c303300197000000000223019f0000000a030000290000000003030433000000000003004b000009c4030000410000000003006019000000000223019f000000000021041b00000011010000290000000201100039000000000201041a000000010220003a0000163c0000613d000000000021041b0000000701000039000000000101041a000000010110003a0000163c0000613d0000000702000039000000000012041b0000000601000039000000000101041a000000400200043d00000020032000390000000000130435000000400120003900000000000104350000000000020435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009c5011001c70000800d0200003900000003030000390000000106000039000009c6040000410000000005000411248e24840000040f000000010020019000001dc50000613d0000000d01000029000000000201043300000ea80000013d0000000103000029000000060030006c00001d6e0000613d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000102000039000000000021041b0000000401000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000202000039000000000021041b0000000101000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b0000000302000039000000000021041b000400070000003d0000000601000029000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d000000000101043b000000000201041a000000000002004b00001d6e0000c13d0000000402000029000000010220027000000003032000290000000604000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000202000029000000000012041b0000000601000039000000000101041a000000000010043f0000001601000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f000000010020019000001dc50000613d0000000b020000290000000002020433000000000101043b000000000021041b0000000d0200002900000000020204330000000103100039000000000023041b0000000e0200002900000000020204330000000203100039000000000023041b0000000a0200002900000000020204330000000303100039000000000023041b000000080200002900000000020204330000000403100039000000000023041b0000000f0200002900000000020204330000000503100039000000000023041b0000000602100039000000000402041a00000a180340019700000007040000290000000004040433000000000004004b000000010330c1bf000000000032041b000000090200002900000000020204330000000703100039000000000023041b00000008011000390000000c020000290000000002020433000009a602200197000000000301041a000009c303300197000000000223019f00000010030000290000000003030433000000000003004b000009c4030000410000000003006019000000000232019f000000000021041b0000000601000039000000000101041a000000400200043d0000004003200039000000640400003900000000004304350000002003200039000000000013043500000005010000290000000000120435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009c5011001c70000800d020000390000000303000039000009c60400004100001a480000013d0000000001000019000024900001043000000020030000390000000004310436000000000302043300000000003404350000004001100039000000000003004b00001e000000613d0000000004000019000000200220003900000000050204330000000076050434000000000661043600000000070704330000000000760435000000400650003900000000060604330000004007100039000000000067043500000060065000390000000006060433000000600710003900000000006704350000008006500039000000000606043300000080071000390000000000670435000000a0065000390000000006060433000000a0071000390000000000670435000000c0065000390000000006060433000000000006004b0000000006000039000000010600c039000000c0071000390000000000670435000000e0065000390000000006060433000000e007100039000000000067043500000100065000390000000006060433000009a6066001970000010007100039000000000067043500000120055000390000000005050433000000000005004b0000000005000039000000010500c0390000012006100039000000000056043500000140011000390000000104400039000000000034004b00001dcf0000413d000000000001042d000000000004004b0000000004000039000000010400c039000000400510003900000000004504350000002004100039000000000034043500000000002104350000006001100039000000000001042d00000000000b004b000000000b000039000000010b00c039000001200c1000390000000000bc0435000009a60aa00197000001000b1000390000000000ab0435000000e00a10003900000000009a0435000000000008004b0000000008000039000000010800c039000000c0091000390000000000890435000000a00810003900000000007804350000008007100039000000000067043500000060061000390000000000560435000000400510003900000000004504350000002004100039000000000034043500000000002104350000014001100039000000000001042d0001000000000002000000000301041a000100000002001d000000000023004b00001e3a0000a13d000000000010043f0000000001000414000009250010009c0000092501008041000000c001100210000009ba011001c70000801002000039248e24890000040f000000010020019000001e400000613d000000000101043b00000001011000290000000002000019000000000001042d00000a1001000041000000000010043f0000003201000039000000040010043f000009b3010000410000249000010430000000000100001900002490000104300000001f0220003900000a17022001970000000001120019000000000021004b00000000020000390000000102004039000009aa0010009c00001e4e0000213d000000010020019000001e4e0000c13d000000400010043f000000000001042d00000a1001000041000000000010043f0000004101000039000000040010043f000009b3010000410000249000010430000000000301001900000000011200a9000000000003004b00001e5b0000613d00000000033100d9000000000023004b00001e5c0000c13d000000000001042d00000a1001000041000000000010043f0000001101000039000000040010043f000009b3010000410000249000010430000000000212004900000a190020009c00001e6b0000213d0000001f0020008c00001e6b0000a13d0000000001010433000000010010008c00001e6b0000213d000000000001042d0000000001000019000024900001043000020000000000020000002101000039000000000201041a0000002301000039000000000101041a0000002203000039000000000303041a000000400500043d000200000005001d0000002404500039000000000034043500000a1a030000410000000003350436000100000003001d00000004035000390000000000130435000009250050009c0000092501000041000000000105401900000040011002100000000003000414000009250030009c0000092503008041000000c003300210000000000113019f000009b6011001c7000009a602200197248e24890000040f000000020b00002900000060031002700000092503300197000000800030008c000000800400003900000000040340190000001f0640018f000000e00740019000000000057b001900001e990000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00001e950000c13d000000000006004b00001ea60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000001ee40000613d0000001f01400039000001e00210018f0000000001b20019000000000021004b00000000020000390000000102004039000009aa0010009c00001ede0000213d000000010020019000001ede0000c13d000000400010043f0000007f0030008c00001edc0000a13d00000a1b0010009c00001ede0000213d0000008002100039000000400020043f00000000020b043300000a1c0020019800000a1d03000041000000000300601900000a1e04200197000000000343019f000000000032004b00001edc0000c13d000000000321043600000001040000290000000004040433000009aa0040009c00001edc0000213d00000000004304350000004003b00039000000000303043300000a1f0030019800000a2004000041000000000400601900000a2105300197000000000454019f000000000043004b00001edc0000c13d0000004004100039000000000034043500000060011000390000006003b000390000000003030433000000000031043500000a190020009c00001f020000213d000000000002004b00001f020000613d000009aa01200197000000000001042d0000000001000019000024900001043000000a1001000041000000000010043f0000004101000039000000040010043f000009b30100004100002490000104300000001f0530018f000009ab06300198000000400200043d000000000462001900001eef0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00001eeb0000c13d000000000005004b00001efc0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000009250020009c00000925020080410000004002200210000000000112019f0000249000010430000000400100043d000000440210003900000a2203000041000000000032043500000024021000390000000d03000039000000000032043500000a23020000410000000000210435000000040210003900000020030000390000000000320435000009250010009c00000925010080410000004001100210000009ee011001c700002490000104300006000000000002000300000001001d0000002101000039000000000201041a0000002301000039000000000101041a0000002203000039000000000303041a000000400500043d000500000005001d0000002404500039000000000034043500000a1a030000410000000003350436000400000003001d00000004035000390000000000130435000009250050009c0000092501000041000000000105401900000040011002100000000003000414000009250030009c0000092503008041000000c003300210000000000113019f000009b6011001c7000009a602200197248e24890000040f000000050b00002900000060031002700000092503300197000000800030008c000000800400003900000000040340190000001f0640018f000000e00740019000000000057b001900001f400000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00001f3c0000c13d000000000006004b00001f4d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000020a60000613d0000001f01400039000001e00210018f0000000001b20019000000000021004b00000000020000390000000102004039000009aa0010009c000020940000213d0000000100200190000020940000c13d000000400010043f0000007f0030008c000020920000a13d00000a1b0010009c000020940000213d0000008002100039000000400020043f00000000040b043300000a1c0040019800000a1d02000041000000000200601900000a1e03400197000000000232019f000600000004001d000000000024004b000020920000c13d0000000602000029000000000221043600000004030000290000000003030433000009aa0030009c000020920000213d00000000003204350000004002b00039000000000202043300000a1f0020019800000a2003000041000000000300601900000a2104200197000000000343019f000000000032004b000020920000c13d0000004003100039000000000023043500000060011000390000006002b0003900000000020204330000000000210435000000400500043d0000000401500039000000060200002900000a190020009c000020b20000213d000000000002004b000020b20000613d0000002502000039000000000202041a000000000300041a000009ec040000410000000000450435000009a602200197000200000002001d0000000000210435000009250050009c0000092501000041000000000105401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009a602300197000009b3011001c7000400000002001d000500000005001d248e24890000040f000000050b00002900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900001fac0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00001fa80000c13d000000000006004b00001fb90000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000020c10000613d0000001f01400039000000600110018f0000000004b10019000000000014004b00000000010000390000000101004039000009aa0040009c000020940000213d0000000100100190000020940000c13d000000400040043f000000200030008c000020920000413d00000000010b0433000500000001001d00000a24010000410000000000140435000009250040009c0000092501000041000000000104401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009bd011001c70000000402000029000400000004001d248e24890000040f000000040b00002900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b001900001fe90000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00001fe50000c13d000000000006004b00001ff60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000020cd0000613d0000001f01400039000000600110018f0000000004b10019000009aa0040009c000020940000213d000000400040043f000000200030008c000020920000413d00000000010b0433000000ff0010008c000020920000213d0000002401000039000000000201041a000009ec010000410000000000140435000000040140003900000002030000290000000000310435000009250040009c0000092501000041000000000104401900000040011002100000000003000414000009250030009c0000092503008041000000c003300210000000000113019f000009b3011001c7000009a602200197000200000002001d000400000004001d248e24890000040f000000040b00002900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000020280000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000020240000c13d000000000006004b000020350000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000020d90000613d0000001f01400039000000600110018f0000000004b10019000009aa0040009c000020940000213d000000400040043f000000200030008c000020920000413d00000000010b0433000100000001001d00000a24010000410000000000140435000009250040009c0000092501000041000000000104401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009bd011001c70000000202000029000400000004001d248e24890000040f000000040b00002900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000020600000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000205c0000c13d000000000006004b0000206d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000020e50000613d0000001f01400039000000600110018f0000000001b10019000009aa0010009c000020940000213d000000400010043f000000200030008c000020920000413d00000000010b0433000000ff0010008c000020920000213d0000000601000029000009aa02100197000000010300002900000000012300a9000000000003004b0000000304000029000020840000613d00000000033100d9000000000023004b000020a00000c13d000000050000006b0000209a0000613d000009c7024000d1000000000004004b0000208c0000613d00000000034200d9000009c70030009c000020a00000c13d0000000503000029000000000013004b0000209a0000213d00000000013100d900000000011200d9000000000001042d0000000001000019000024900001043000000a1001000041000000000010043f0000004101000039000000040010043f000009b301000041000024900001043000000a1001000041000000000010043f0000001201000039000000040010043f000009b301000041000024900001043000000a1001000041000000000010043f0000001101000039000000040010043f000009b30100004100002490000104300000001f0530018f000009ab06300198000000400200043d0000000004620019000020f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000020ad0000c13d000020f00000013d00000a2302000041000000000025043500000020020000390000000000210435000000440150003900000a2202000041000000000021043500000024015000390000000d020000390000000000210435000009250050009c00000925050080410000004001500210000009ee011001c700002490000104300000001f0530018f000009ab06300198000000400200043d0000000004620019000020f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000020c80000c13d000020f00000013d0000001f0530018f000009ab06300198000000400200043d0000000004620019000020f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000020d40000c13d000020f00000013d0000001f0530018f000009ab06300198000000400200043d0000000004620019000020f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000020e00000c13d000020f00000013d0000001f0530018f000009ab06300198000000400200043d0000000004620019000020f00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000020ec0000c13d000000000005004b000020fd0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000009250020009c00000925020080410000004002200210000000000112019f0000249000010430000009a606100198000021170000613d000009b101000041000000000201041a000009ad03200197000000000363019f000000000031041b0000000001000414000009a605200197000009250010009c0000092501008041000000c001100210000009a7011001c70000800d020000390000000303000039000009d604000041248e24840000040f00000001002001900000211c0000613d000000000001042d000009de01000041000000000010043f000000040000043f000009b301000041000024900001043000000000010000190000249000010430000009b101000041000000000101041a000009a6021001970000000001000411000000000012004b000021250000c13d000000000001042d000009b202000041000000000020043f000000040010043f000009b30100004100002490000104300004000000000002000200000001001d0000000001000415000100000001001d0000000b01000039000000000101041a000000000001004b0000000a02000039000021890000613d0000000401000039000000000101041a000000000302041a000000000113004b000021ef0000413d0000001e02000039000000000202041a000000000002004b000021f50000613d00000000012100d9000000ff0010008c000021ef0000213d000400000003001d0000001f02000039000000000202041a0003000000120237000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000021fb0000613d000000000101043b0000000406000029000000000016004b000021950000813d0000000402000039000000000202041a000000000426004b0000000307000029000021ef0000413d0000001e03000039000000000303041a000000000003004b000021f50000613d00000000043400d9000000010540003a000021ef0000613d00000000043500a900000000055400d9000000000035004b000021ef0000c13d000000000024001a000021ef0000413d0000000003240019000000000013004b00000000020100190000000002034019000000000462004b000021ef0000413d000000000007004b000021770000613d00000000054700a900000000067500d9000000000046004b000021ef0000c13d000000000005004b000021770000613d000009c7045000d100000000055400d9000009c70050009c000021780000613d000021ef0000013d00000000040000190000000b05000039000000000505041a000000000005004b000021f50000613d00000000045400d90000000c05000039000000000505041a000000000045001a000021ef0000413d00000000044500190000000c05000039000000000045041b000000000013004b000000010770a270000300000007001d000400000002001d000021430000013d000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f0000000100200190000021fb0000613d000000000101043b0000000a02000039000000000012041b0000000001000415000000010110006900000000010000020000000201000029000009a601100197000400000001001d000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f0000000100200190000021fc0000613d0000000c02000039000000000202041a000200000002001d000000000101043b000000000101041a000300000001001d0000001201000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f0000000100200190000021fc0000613d000000000101043b000000000101041a000000020110006b0000000302000029000021ef0000413d00000000032100a9000000000002004b000021c50000613d00000000022300d9000000000012004b000021ef0000c13d000300000003001d0000000401000029000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f0000000100200190000021fc0000613d0000000302000029000009c70220012a000000000101043b000000000301041a000000000023001a000021ef0000413d0000000002230019000000000021041b0000000c01000039000000000101041a000300000001001d0000000401000029000000000010043f0000001201000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f0000000100200190000021fc0000613d000000000101043b0000000302000029000000000021041b000000000001042d00000a1001000041000000000010043f0000001101000039000000040010043f000009b301000041000024900001043000000a1001000041000000000010043f0000001201000039000000040010043f000009b3010000410000249000010430000000000001042f000000000100001900002490000104300005000000000002000500000002001d000100000001001d000000000200041a000000400300043d000400000003001d00000a25010000410000000000130435000009250030009c0000092501000041000000000103401900000040011002100000000003000414000009250030009c0000092503008041000000c003300210000000000113019f000009bd011001c7000009a602200197248e24840000040f000000040b00002900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000022220000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000221e0000c13d000000000006004b0000222f0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000022c50000613d0000001f01400039000000600110018f0000000004b10019000000000014004b00000000010000390000000101004039000009aa0040009c000022b90000213d0000000100100190000022b90000c13d000000400040043f0000001f0030008c000022b70000a13d00000000010b0433000200000001001d000000000200041a00000a26010000410000000000140435000009250040009c0000092501000041000000000104401900000040011002100000000003000414000009250030009c0000092503008041000000c003300210000000000113019f000009bd011001c7000009a602200197000400000002001d000300000004001d248e24890000040f000000030b00002900000060031002700000092503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000022610000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000225d0000c13d000000000006004b0000226e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000022d10000613d0000001f01400039000000600110018f0000000001b10019000009aa0010009c000022b90000213d000000400010043f000000200030008c000022b70000413d00000000020b04330000000203000029000000000032001a000022bf0000413d00000000023200190000000503200029000000000023004b00000000020000390000000102004039000000010020008c000022bf0000613d0000002002000039000000000402041a00000a280440009c000022bf0000813d000000000043004b000022eb0000213d000009d1010000410000000000100443000000040100002900000004001004430000000001000414000009250010009c0000092501008041000000c001100210000009d2011001c70000800202000039248e24890000040f0000000100200190000023030000613d000000000101043b000000000001004b000022b70000613d000000400300043d00000024013000390000000502000029000000000021043500000a290100004100000000001304350000000101000029000009a60110019700000004023000390000000000120435000009250030009c000500000003001d0000092501000041000000000103401900000040011002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009b6011001c70000000402000029248e24840000040f0000000100200190000023040000613d0000000501000029000009aa0010009c000022b90000213d000000400010043f000000000001042d0000000001000019000024900001043000000a1001000041000000000010043f0000004101000039000000040010043f000009b301000041000024900001043000000a1001000041000000000010043f0000001101000039000000040010043f000009b30100004100002490000104300000001f0530018f000009ab06300198000000400200043d0000000004620019000022dc0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000022cc0000c13d000022dc0000013d0000001f0530018f000009ab06300198000000400200043d0000000004620019000022dc0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000022d80000c13d000000000005004b000022e90000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f000000000014043500000060013002100000231f0000013d000000a40310003900000a2a040000410000000000430435000000840310003900000a2b040000410000000000430435000000640310003900000a2c040000410000000000430435000000440310003900000a2d04000041000000000043043500000024031000390000006204000039000000000043043500000a2303000041000000000031043500000004031000390000000000230435000009250010009c0000092501008041000000400110021000000a2e011001c70000249000010430000000000001042f00000060061002700000001f0460018f000009ab05600198000000400200043d0000000003520019000023100000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b0000230c0000c13d0000092506600197000000000004004b0000231e0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000009250020009c00000925020080410000004002200210000000000112019f00002490000104300005000000000002000300000002001d000200000001001d0000000501000039000000000201041a000000ff002001900000234e0000c13d00000001022001bf000000000021041b000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f00000001002001900000246b0000613d000000000101043b0000000402000039000000000012041b0000000a02000039000000000012041b000000400200043d0000000000120435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009ba011001c70000800d02000039000000010300003900000a2f04000041248e24840000040f00000001002001900000246c0000613d0000000001000415000100000001001d0000000b01000039000000000101041a000000000001004b000023ab0000613d0000000401000039000000000101041a0000000a02000039000000000302041a000000000113004b0000245f0000413d0000001e02000039000000000202041a000000000002004b000024650000613d00000000012100d9000000ff0010008c0000245f0000213d000500000003001d0000001f02000039000000000202041a0004000000120237000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f00000001002001900000246b0000613d000000000101043b0000000506000029000000000016004b000023b70000813d0000000402000039000000000202041a000000000426004b00000004070000290000245f0000413d0000001e03000039000000000303041a000000000003004b000024650000613d00000000043400d9000000010540003a0000245f0000613d00000000043500a900000000055400d9000000000035004b0000245f0000c13d000000000024001a0000245f0000413d0000000003240019000000000013004b00000000020100190000000002034019000000000462004b0000245f0000413d000000000007004b000023990000613d00000000057400a900000000067500d9000000000046004b0000245f0000c13d000000000005004b000023990000613d000009c7045000d100000000055400d9000009c70050009c0000239a0000613d0000245f0000013d00000000040000190000000b05000039000000000505041a000000000005004b000024650000613d00000000045400d90000000c05000039000000000505041a000000000045001a0000245f0000413d00000000044500190000000c05000039000000000045041b000000000013004b000000010770a270000400000007001d000500000002001d000023650000013d000009cd0100004100000000001004430000000001000414000009250010009c0000092501008041000000c001100210000009c0011001c70000800b02000039248e24890000040f00000001002001900000246b0000613d000000000101043b0000000a02000039000000000012041b0000000001000415000000010110006900000000010000020000000201000029000009a601100197000500000001001d000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d0000000c02000039000000000202041a000200000002001d000000000101043b000000000101041a000400000001001d0000001201000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d000000000101043b000000000101041a000000020110006b00000004020000290000245f0000413d00000000032100a9000000000002004b000023e70000613d00000000022300d9000000000012004b0000245f0000c13d000400000003001d0000000501000029000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d0000000402000029000009c70220012a000000000101043b000000000301041a000000000023001a0000245f0000413d0000000002230019000000000021041b0000000c01000039000000000101041a000400000001001d0000000501000029000000000010043f0000001201000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d000000000101043b0000000402000029000000000021041b0000000b01000039000000000101041a000000030010002a0000245f0000413d00000003011000290000000b02000039000000000012041b0000000501000029000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d000000000101043b000000000201041a000000030020002a0000245f0000413d0000000302200029000000000021041b0000000501000029000000000010043f0000001001000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d000000000101043b000000000101041a000400000001001d0000000501000029000000000010043f0000001101000039000000200010043f0000000001000414000009250010009c0000092501008041000000c001100210000009a5011001c70000801002000039248e24890000040f00000001002001900000246c0000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000004010000290000000000120435000009250020009c000009250200804100000040012002100000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009a5011001c70000800d020000390000000203000039000000000500041100000a3004000041248e24840000040f00000001002001900000246c0000613d000000000001042d00000a1001000041000000000010043f0000001101000039000000040010043f000009b301000041000024900001043000000a1001000041000000000010043f0000001201000039000000040010043f000009b3010000410000249000010430000000000001042f00000000010000190000249000010430000000000001042f000009250010009c00000925010080410000004001100210000009250020009c00000925020080410000006002200210000000000112019f0000000002000414000009250020009c0000092502008041000000c002200210000000000112019f000009a7011001c70000801002000039248e24890000040f0000000100200190000024820000613d000000000101043b000000000001042d0000000001000019000024900001043000002487002104210000000102000039000000000001042d0000000002000019000000000001042d0000248c002104230000000102000039000000000001042d0000000002000019000000000001042d0000248e000004320000248f0001042e000024900001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0000000200000000000000000000000000000040000001000000000000000000000000000000000000000000000000000000000000000000000000006d12ff5100000000000000000000000000000000000000000000000000000000bddf889400000000000000000000000000000000000000000000000000000000d9d3a8a800000000000000000000000000000000000000000000000000000000e681c93300000000000000000000000000000000000000000000000000000000ea26fa2c00000000000000000000000000000000000000000000000000000000ea26fa2d00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000fc1e62f500000000000000000000000000000000000000000000000000000000e681c93400000000000000000000000000000000000000000000000000000000e80d7fec00000000000000000000000000000000000000000000000000000000e92820e600000000000000000000000000000000000000000000000000000000e0d152ae00000000000000000000000000000000000000000000000000000000e0d152af00000000000000000000000000000000000000000000000000000000e35514ba00000000000000000000000000000000000000000000000000000000e4ea36f000000000000000000000000000000000000000000000000000000000d9d3a8a900000000000000000000000000000000000000000000000000000000da01ff3300000000000000000000000000000000000000000000000000000000dd6a4c6500000000000000000000000000000000000000000000000000000000c51a2bb900000000000000000000000000000000000000000000000000000000d0d6872900000000000000000000000000000000000000000000000000000000d0d6872a00000000000000000000000000000000000000000000000000000000d147129600000000000000000000000000000000000000000000000000000000d30c3ed400000000000000000000000000000000000000000000000000000000c51a2bba00000000000000000000000000000000000000000000000000000000c8b87ca800000000000000000000000000000000000000000000000000000000ca18117000000000000000000000000000000000000000000000000000000000c062c90a00000000000000000000000000000000000000000000000000000000c062c90b00000000000000000000000000000000000000000000000000000000c0f9acc500000000000000000000000000000000000000000000000000000000c243589400000000000000000000000000000000000000000000000000000000bddf889500000000000000000000000000000000000000000000000000000000c032a9340000000000000000000000000000000000000000000000000000000084ae2bc5000000000000000000000000000000000000000000000000000000009ca423b200000000000000000000000000000000000000000000000000000000a9f8d18000000000000000000000000000000000000000000000000000000000a9f8d18100000000000000000000000000000000000000000000000000000000aef39abf00000000000000000000000000000000000000000000000000000000bd611496000000000000000000000000000000000000000000000000000000009ca423b3000000000000000000000000000000000000000000000000000000009d52cb21000000000000000000000000000000000000000000000000000000009fe660b0000000000000000000000000000000000000000000000000000000008da5cb5a000000000000000000000000000000000000000000000000000000008da5cb5b0000000000000000000000000000000000000000000000000000000094fc19e4000000000000000000000000000000000000000000000000000000009618b31c0000000000000000000000000000000000000000000000000000000084ae2bc60000000000000000000000000000000000000000000000000000000086b3cd260000000000000000000000000000000000000000000000000000000088e8e6fa0000000000000000000000000000000000000000000000000000000072d298ba000000000000000000000000000000000000000000000000000000007e08b5b2000000000000000000000000000000000000000000000000000000007e08b5b300000000000000000000000000000000000000000000000000000000811c5089000000000000000000000000000000000000000000000000000000008129fc1c0000000000000000000000000000000000000000000000000000000072d298bb00000000000000000000000000000000000000000000000000000000787a08a6000000000000000000000000000000000000000000000000000000007a1728d600000000000000000000000000000000000000000000000000000000713494d600000000000000000000000000000000000000000000000000000000713494d700000000000000000000000000000000000000000000000000000000715018a60000000000000000000000000000000000000000000000000000000072779cba000000000000000000000000000000000000000000000000000000006d12ff52000000000000000000000000000000000000000000000000000000006d3d5393000000000000000000000000000000000000000000000000000000003ccfd60a0000000000000000000000000000000000000000000000000000000053d6103c000000000000000000000000000000000000000000000000000000005fd9491c000000000000000000000000000000000000000000000000000000006756a1c6000000000000000000000000000000000000000000000000000000006756a1c70000000000000000000000000000000000000000000000000000000067c9b0170000000000000000000000000000000000000000000000000000000069f0ee33000000000000000000000000000000000000000000000000000000005fd9491d00000000000000000000000000000000000000000000000000000000613ba7600000000000000000000000000000000000000000000000000000000062de3bd1000000000000000000000000000000000000000000000000000000005717b731000000000000000000000000000000000000000000000000000000005717b7320000000000000000000000000000000000000000000000000000000059058ad1000000000000000000000000000000000000000000000000000000005a5ccef00000000000000000000000000000000000000000000000000000000053d6103d00000000000000000000000000000000000000000000000000000000542f9e6a00000000000000000000000000000000000000000000000000000000553dcbbd0000000000000000000000000000000000000000000000000000000048cd4cb0000000000000000000000000000000000000000000000000000000004e378957000000000000000000000000000000000000000000000000000000004e378958000000000000000000000000000000000000000000000000000000004f0e0ef3000000000000000000000000000000000000000000000000000000004fc3f41a0000000000000000000000000000000000000000000000000000000048cd4cb1000000000000000000000000000000000000000000000000000000004bd0e379000000000000000000000000000000000000000000000000000000004bda97da000000000000000000000000000000000000000000000000000000003e89bb12000000000000000000000000000000000000000000000000000000003e89bb130000000000000000000000000000000000000000000000000000000040f5da9e0000000000000000000000000000000000000000000000000000000041a0894d000000000000000000000000000000000000000000000000000000003ccfd60b000000000000000000000000000000000000000000000000000000003d16f609000000000000000000000000000000000000000000000000000000002107f974000000000000000000000000000000000000000000000000000000002fc96ce50000000000000000000000000000000000000000000000000000000032cb6b0b0000000000000000000000000000000000000000000000000000000032cb6b0c00000000000000000000000000000000000000000000000000000000372500ab000000000000000000000000000000000000000000000000000000003b714199000000000000000000000000000000000000000000000000000000002fc96ce60000000000000000000000000000000000000000000000000000000030775a940000000000000000000000000000000000000000000000000000000031d7a2620000000000000000000000000000000000000000000000000000000026b825d10000000000000000000000000000000000000000000000000000000026b825d2000000000000000000000000000000000000000000000000000000002c359209000000000000000000000000000000000000000000000000000000002ebf3d6e000000000000000000000000000000000000000000000000000000002107f97500000000000000000000000000000000000000000000000000000000234f3f1b000000000000000000000000000000000000000000000000000000002461ca5900000000000000000000000000000000000000000000000000000000157e204b000000000000000000000000000000000000000000000000000000001a267cd1000000000000000000000000000000000000000000000000000000001a267cd2000000000000000000000000000000000000000000000000000000001e57057d00000000000000000000000000000000000000000000000000000000202fb05000000000000000000000000000000000000000000000000000000000157e204c000000000000000000000000000000000000000000000000000000001755ff210000000000000000000000000000000000000000000000000000000018431dde000000000000000000000000000000000000000000000000000000000ccf2155000000000000000000000000000000000000000000000000000000000ccf21560000000000000000000000000000000000000000000000000000000010d967590000000000000000000000000000000000000000000000000000000012719c6b0000000000000000000000000000000000000000000000000000000006257080000000000000000000000000000000000000000000000000000000000b5a0fdc0000000000000000000000000000000000000000000000000000000018fb586402000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000000000000fbb67fda52d4bfb8bf0200000000000000000000000000000000000040000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000003ffffffe0000000000000000000000000000000000000000000000000ffffffffffffffff00000000000000000000000000000000000000000000000000000000ffffffe07e88d2a81696453849a2b46e8b04e17d88735ac6822ad461ad70d0b83a2e09aaffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000d8e128775b7d140e398e926eac4a340f22911251358cb8069551f12bc0f5ab619016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300118cdaa7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000a9059cbb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000800000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000800000000000000000acd28bd76121326a9c13dcb739c4632431262fe21dd53bc297abf4c60b03445c02000000000000000000000000000000000000200000000000000000000000000bd772fd008a8dd5673c42a4f50f72220b2603eee55113cd6c38ff78d71e644fedd999f8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320200000200000000000000000000000000000004000000000000000000000000e424ed553a53c3a900c875ed34d63043e4dfb799427ee8ae0836b046a603c90e000000000000000000000000000000000000000000000000fffffffffffffebfffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000020000000000000000000000000000000000006000000000000000000000000002c783c8f6fb950cd4c364db52f36a1823b864f2ef1790005074c61d9a46cf400000000000000000000000000000000000000000000000000de0b6b3a7640000ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffd0a7ceb410ade2d440d8ed59d6b338fe480f98025101655790e0de736edddabea800e0ac00000000000000000000000000000000000000000000000000000000a20593b80000000000000000000000000000000000000000000000000000000003671d74657ab1acda7e2472be1252af630eae6aba395b0cb64302ee5f1e20a242cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd1a3ba90dab2a94b799931cc7fdbfe68eb1ae3716f001c082a23be2c7edc594647f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a000000000000000000000000000000000000000000000000ff00000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000100000000000000018be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000a688906bd8b00000000000000000000000000000000000000000000000000000000000000632ea000000000000000000000000000000000000000000000000006f05b59d3b20000ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d21e4fbdf700000000000000000000000000000000000000000000000000000000d7e6bcf800000000000000000000000000000000000000000000000000000000f92ee8a900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000354a6ba7a180000000000000000000000000000000000000000000000000000de0b6b3a764000158d620b300000000000000000000000000000000000000000000000000000000f721e9425607d38abda58b925d2a080b3aefa127d46973d2683875dc87cb9a6bf1fa1762000000000000000000000000000000000000000000000000000000006cb4090800000000000000000000000000000000000000000000000000000000f920b24ea96b3814655944622f9eb86875e3193c5de1a9de018777e6c8705cee4705d684000000000000000000000000000000000000000000000000000000003a6c77df0000000000000000000000000000000000000000000000000000000070a082310000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000042966c68000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fbb67fda52d4bfb8be3b87f10900000000000000000000000000000000000000000000000000000000347a455f665e43e98ee1b326fbba1f863e4872048da2e7c5aecc7b3ca7d4be1b00f5f14a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000800000000000000000503d0a5de9a7f19ca01f785cf229248bbcc040ff7abac38f7614777452a81c0100000000000000000000000000000000000000000000000000000000ad251c2700000000000000000000000000000000000000040000001c0000000000000000d2ade556000000000000000000000000000000000000000000000000000000008fe6f7d800000000000000000000000000000000000000000000000000000000611042280000000000000000000000000000000000000000000000000000000086db792d000000000000000000000000000000000000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f39750b219c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f5a267f13d9f63cb000000000000000000000000000000000000000000000000000000001b100e580000000000000000000000000000000000000000000000000000000093e959f04e9258f824be3dc131d63051e7b16cc10c7f98bed3bdbe97f82d92a6e331ada0d0e61e9a4196bf4994f2519193d70a601daff346c4276d591664da9a15f3da3000000000000000000000000000000000000000000000000000000000aa8a9b9800000000000000000000000000000000000000000000000000000000fc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe0df723dc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b4c0595a86aa1c100000047cd2fa60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bac65e5be2dbc44c627e3876b04b29d12596a77c7d0fa585ccb754b9fcd92e48d813dd77ff0b21e6000000000000000000000000000000000000000000000000000000005168e68f0000000000000000000000000000000000000000000000000000000041fde9ef0000000000000000000000000000000000000000000000000000000072932dd3000000000000000000000000000000000000000000000000000000000c02d44e000000000000000000000000000000000000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000602fe2ca00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf00000000000000000000000000000000000000000000003fffffffffffffffe000000000000000000000000000000000000000000000000200000000000000004e23d03500000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa4ae35e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f0000000000000000000000000000000000000000000000008000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffffffffffffff0000000000000000000000000000000000000000000000000000000080000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffffff496e76616c69642070726963650000000000000000000000000000000000000008c379a000000000000000000000000000000000000000000000000000000000313ce567000000000000000000000000000000000000000000000000000000000a7d242c0000000000000000000000000000000000000000000000000000000018160ddd00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffe4b3fa6a57955e3effffffffffffffffffffffffffffffffffffffffffffffffe4b3fa6a57955e3f00000040c10f19000000000000000000000000000000000000000000000000000000006c79000000000000000000000000000000000000000000000000000000000000756e74206d757374206e6f742065786365656420746865206d6178207375707020616d6f756e74206275726e65642c20616e6420746865206d696e7420616d6f5468652073756d206f662074686520746f74616c20737570706c792c2074686500000000000000000000000000000000000000c4000000000000000000000000daae9aa758637a0d349f036f099afd70aa88d8ac63fce096321de512ffebc16ca051d58ced8df58040b29d2c939da70a826ae40290f77c9a66b38b8b85315f650000000000000000000000000000000000000000000000000000000000000000000000000000000000a2646970667358221220bbbd4e1c79d56cf6fdc1ac7744af6d12d6c2394e3f0be6c20de688a94ac49afc64736f6c6378247a6b736f6c633a312e352e31353b736f6c633a302e382e32363b6c6c766d3a312e302e320055
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.