ETH Price: $2,858.29 (-10.11%)
Gas: 14 Gwei

Token

this (this)
 

Overview

Max Total Supply

333,000,000,000 this

Holders

150

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
113,308,692.207663215114075511 this

Value
$0.00
0x3c2ee64612b2b1bcce22e43459c9474c0f56384b
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
ThisToken

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 9999 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-07-15
*/

// SPDX-License-Identifier: UNLICENSED

/*
  █▓▒▒░░░ this is this contract. ░░░▒▒▓█

  copyright (c) 2023 this.
*/

// File: contracts/interfaces/IThisToken.sol

pragma solidity 0.8.19;

interface IThisToken {
  event SwapAndLiquifyModuleToggle(bool enabled);

  /* -===== MUTATIVE FUNCTIONS ------ */

  function toggleLaunchProtectionModule(bool enabled)
    external;

  function enableTrading()
    external;

  function setMaxTransactionPercentage(uint256 maxTransactionPercentage)
    external;

  function setMaxBalancePercentage(uint256 maxBalancePercentage)
    external;

  function toggleSwapAndLiquifyModule(bool enabled)
    external;

  function setAutomatedMarketMakerPair(address pairAddress, bool isAMM)
    external;

  function setBridgeTheGapWallet(address newWallet)
    external;

  function setLiquidityWallet(address newWallet)
    external;

  function redeemLockedETH(address recipient)
    external;

  // withdraw any tokens that are not supposed to be inside this contract.
  function redeemLockedTokens(address _recipient, address _token)
    external;
}

// File: contracts/interfaces/IUserFeatures.sol

pragma solidity 0.8.19;

interface IUserFeatures {
  function isExcludedFrom(bytes32 feature, address account)
    external
    view
    returns(bool);

  /* -===== MUTATIVE FUNCTIONS ------ */

  function setupUserInclusions(address account, bytes32[] calldata)
    external;

  function setupUserExclusions(address account, bytes32[] calldata)
    external;
}

// File: contracts/storages/UserFeaturesStorage.sol

pragma solidity 0.8.19;

library UserFeaturesStorage {
  bytes32 private constant MODULE_STORAGE_POSITION = keccak256('user.features.storage');

  struct Storage {
    mapping(address => mapping(bytes32 => bool)) userFeatures;
  }

  function getStorage() internal pure returns(Storage storage st) {
    bytes32 position = MODULE_STORAGE_POSITION;

    assembly {
      st.slot := position
    }
  }
}

// File: contracts/storages/ThisTokenStorage.sol

pragma solidity 0.8.19;

library ThisTokenStorage {
  bytes32 private constant MODULE_STORAGE_POSITION = keccak256('thisToken.storage');

  struct Storage {
    bool initialized;
    bool tradingEnabled;
    bool initialLiquidityAdded;

    bool maxBalanceEnabled;
    uint256 maxBalanceAmount;
    uint256 maxTransactionAmount;

    bool launchProtectionModuleEnabled;
    uint256 launchBlockAmount;
    uint256 initialLiquidityBlockNumber;
  }

  function initializeDefaults() internal {
    Storage storage st = getStorage();

    st.initialized = true;
    st.tradingEnabled = false;
    st.initialLiquidityAdded = false;

    st.launchProtectionModuleEnabled = true;
    st.launchBlockAmount = 35;
    st.initialLiquidityBlockNumber = 0;
  }

  function getStorage() internal pure returns(Storage storage st) {
    bytes32 position = MODULE_STORAGE_POSITION;

    assembly {
      st.slot := position
    }
  }
}

// File: @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol

pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

// File: @uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol

pragma solidity >=0.6.2;

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

// File: @uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol

pragma solidity >=0.5.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}

// File: @openzeppelin/contracts/utils/Address.sol

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: contracts/storages/ERC20BaseStorage.sol

pragma solidity 0.8.19;

library ERC20BaseStorage {
  bytes32 private constant MODULE_STORAGE_POSITION = keccak256('erc20.base.storage');
  bytes32 private constant TX_LAUNCH_PROTECTION = keccak256('TX_LAUNCH_PROTECTION');

  struct User {
    uint256 balance;
    mapping(address => uint256) allowances;
  }

  struct Fee {
    uint256 totalFee;
    uint256 platformFee;
    uint256 liquidityFee;
  }

  struct Storage {
    string name;
    string symbol;

    uint8 decimals;
    uint256 totalSupply;

    mapping(address => User) users;
    mapping(address => bool) automatedMarketMakerPairs;

    mapping(bytes32 => Fee) fees;
    Fee collectedFees;

    address platformWallet;
    address liquidityWallet;

    IUniswapV2Router02 uniswapV2Router;
    address uniswapV2Pair;

    IERC20 basePair;

    uint256 contractRedeemableETH;
    uint256 contractRedeemableBasePair;

    bool inSwapAndLiquify;
    bool liquidityModuleEnabled;
    uint256 tokenReserveThreshold;

    address swapHelper;
  }

  function initializeDefaults() internal {
    Storage storage st = getStorage();

    st.decimals = 18;
    st.liquidityModuleEnabled = true;
  
    st.fees[TX_LAUNCH_PROTECTION] = Fee({
      totalFee: 45_000,
      platformFee: 44_000,
      liquidityFee: 1_000
    });
  }

  function getStorage() internal pure returns(Storage storage st) {
    bytes32 position = MODULE_STORAGE_POSITION;

    assembly {
      st.slot := position
    }
  }
}

// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol

pragma solidity ^0.8.0;

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// File: contracts/interfaces/IERC20Base.sol

pragma solidity 0.8.19;

interface IERC20Base is IERC20Metadata {
  event LiquidityModuleToggled(bool enabled);
  event SetAutomatedMarketMakerPair(address pairAddress, bool isAMM);

  event AddLiquidity(uint256 amountInTokens, uint256 amountInWETH);

  function getTransactionFees(address sender, address recipient)
    external
    view
    returns(
      bytes32 feeType,
      uint256 totalFee,
      uint256 liquidityFee,
      uint256 platformFee
    );

  function getCollectedFees()
    external
    view
    returns(
      uint256 totalFee,
      uint256 liquidityFee,
      uint256 platformFee
    );

  /* -===== MUTATIVE FUNCTIONS ------ */

  function changeFees(
    bytes32 txType,
    uint256 liquidityFee,
    uint256 platformFee
  ) external;

  function toggleLiquidityModule(bool _enabled)
    external;

  function setTokenReserveThreshold(uint256 _liquidityThresholdPercentage)
    external;
}

// File: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

pragma solidity ^0.8.0;

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// File: @openzeppelin/contracts/utils/math/Math.sol

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

// File: contracts/utils/Percentages.sol

pragma solidity 0.8.19;

// 100 * 10 * 1000000000 / 100000000000000000

// 1 * 1 * 1 / 100000

// 1 / 100000

library Percentages {
  uint256 private constant PERCENTAGE_UNITS = 1e18;
  uint256 private constant PERCENTAGE_DIVISOR = (PERCENTAGE_UNITS * 100000);

  function getRate(uint256 a, uint256 b) internal pure returns(uint256) {
    if(b == 0) {
      return 0;
    }

    return (a * PERCENTAGE_UNITS) / b;
  }

  function fromRate(uint256 number, uint256 rate) internal pure returns(uint256) {
    return (number * rate) / PERCENTAGE_UNITS;
  }

  function fraction(uint256 number, uint256 perc) internal pure returns(uint256) {
    require(perc <= 100_000, 'INVALID_PERCENTAGE'); // we do not want fractions above 100%
    return (number * perc * PERCENTAGE_UNITS) / PERCENTAGE_DIVISOR;
  }
}

// File: @openzeppelin/contracts/utils/structs/EnumerableSet.sol

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: @openzeppelin/contracts/utils/introspection/ERC165.sol

pragma solidity ^0.8.0;

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// File: @openzeppelin/contracts/utils/Strings.sol

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant alphabet = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = alphabet[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

}

// File: @openzeppelin/contracts/utils/Context.sol

pragma solidity ^0.8.0;

/*
 * @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 Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol

pragma solidity ^0.8.0;

/**
 * @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.
 *
 * By default, the owner account will be the one that deploys the contract. 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 Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = 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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File: contracts/SwapHelper.sol

pragma solidity 0.8.19;

/**
 * @dev This tiny helper is meant to be a layer between the Uniswap LP Pair and Uniswap V2 Router
 * This is due to the LP Pair contract not allowing direct transfers from the token contract
 * and its own LP Pair, when trading WETH. As we are using WETH instead of ETH to save gas
 * once the contract triggers its own swapping mechanism for liquidity and other fees, we have to
 * use a child contract to hold the swapped tokens and then collect them right after.
 */
contract SwapHelper is Ownable {
  function approve(IERC20 _token, uint256 _amount) external onlyOwner {
    _token.approve(msg.sender, _amount);
  }
}

// File: @openzeppelin/contracts/access/AccessControl.sol

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    function hasRole(bytes32 role, address account) external view returns (bool);
    function getRoleAdmin(bytes32 role) external view returns (bytes32);
    function grantRole(bytes32 role, address account) external;
    function revokeRole(bytes32 role, address account) external;
    function renounceRole(bytes32 role, address account) external;
}

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping (address => bool) members;
        bytes32 adminRole;
    }

    mapping (bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId
            || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
     */
    function _checkRole(bytes32 role, address account) internal view {
        if(!hasRole(role, account)) {
            revert(string(abi.encodePacked(
                "AccessControl: account ",
                Strings.toHexString(uint160(account), 20),
                " is missing role ",
                Strings.toHexString(uint256(role), 32)
            )));
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
        _roles[role].adminRole = adminRole;
    }

    function _grantRole(bytes32 role, address account) private {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// File: @openzeppelin/contracts/access/AccessControlEnumerable.sol

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable {
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping (bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId
            || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {grantRole} to track enumerable memberships
     */
    function grantRole(bytes32 role, address account) public virtual override {
        super.grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {revokeRole} to track enumerable memberships
     */
    function revokeRole(bytes32 role, address account) public virtual override {
        super.revokeRole(role, account);
        _roleMembers[role].remove(account);
    }

    /**
     * @dev Overload {renounceRole} to track enumerable memberships
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        super.renounceRole(role, account);
        _roleMembers[role].remove(account);
    }

    /**
     * @dev Overload {_setupRole} to track enumerable memberships
     */
    function _setupRole(bytes32 role, address account) internal virtual override {
        super._setupRole(role, account);
        _roleMembers[role].add(account);
    }
}

// File: contracts/UserFeatures.sol

pragma solidity 0.8.19;

abstract contract UserFeatures is
  /* -=== IMMUTABLE ===- */
  /* -=== DO NOT CHANGE ORDER ===- */
  /* -=== IT WILL BREAK STORAGE ===- */

  IUserFeatures,

  /* -=== IMMUTABLE ===- */
  /* -=== DO NOT CHANGE ORDER ===- */
  /* -=== IT WILL BREAK STORAGE ===- */

  AccessControlEnumerable
{
  bytes32 internal constant FEATURE_FEE = keccak256('FEATURE_FEE');
  bytes32 internal constant FEATURE_MAXTX = keccak256('FEATURE_MAXTX');
  bytes32 internal constant FEATURE_MAXBALANCE = keccak256('FEATURE_MAXBALANCE');
  bytes32 internal constant FEATURE_DIVIDENDS = keccak256('FEATURE_DIVIDENDS');

  function isExcludedFrom(bytes32 feature, address account)
    public
    view
    override
    returns(bool)
  {
    return UserFeaturesStorage.getStorage().userFeatures[account][feature];
  }

  /* -===== MUTATIVE FUNCTIONS ------ */

  function setupUserInclusions(address account, bytes32[] memory items)
    public
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    _setupUserFeatures(account, items, false);
  }

  function setupUserExclusions(address account, bytes32[] memory items)
    public
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    _setupUserFeatures(account, items, true);
  }

  function _setupUserFeatures(address account, bytes32[] memory items, bool excluded) private {
    for(uint256 i = 0; i < items.length; i += 1) {
      UserFeaturesStorage.getStorage().userFeatures[account][items[i]] = excluded;
    }
  }
}

// File: contracts/ERC20Base.sol

pragma solidity 0.8.19;

abstract contract ERC20Base is
  /* -=== IMMUTABLE ===- */
  /* -=== DO NOT CHANGE ORDER ===- */
  /* -=== IT WILL BREAK STORAGE ===- */

  IERC20Base,

  /* -=== IMMUTABLE ===- */
  /* -=== DO NOT CHANGE ORDER ===- */
  /* -=== IT WILL BREAK STORAGE ===- */

  AccessControlEnumerable,
  UserFeatures
{
  using Percentages for uint256;
  using SafeERC20 for IERC20;

  struct FeeProcessingQueue {
    uint256 totalAmount;

    uint256 platformRate;
    uint256 platformSwapAmount;

    uint256 liquidityRate;
    uint256 liquiditySwapAmount;
    uint256 liquidityAddAmount;
  }

  bytes32 internal constant LIQUIFY_BYPASSER_ROLE = keccak256('LIQUIFY_BYPASSER_ROLE');

  bytes32 internal constant TX_BUY = keccak256('TX_BUY');
  bytes32 internal constant TX_SELL = keccak256('TX_SELL');
  bytes32 internal constant TX_TRANSFER = keccak256('TX_TRANSFER');
  bytes32 internal constant TX_FREE = keccak256('TX_FREE');
  bytes32 internal constant TX_LAUNCH_PROTECTION = keccak256('TX_LAUNCH_PROTECTION');

  constructor(
    string memory _name,
    string memory _symbol,

    uint256 _supply,
    uint256 _liquidityThresholdPercentage,
    address _v2RouterAddress,
    address _basePairAddress
  ) {
    ERC20BaseStorage.initializeDefaults();
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    erc20.name = _name;
    erc20.symbol = _symbol;
    erc20.decimals = 18;
    erc20.totalSupply = _supply * (10**uint256(erc20.decimals));
    erc20.tokenReserveThreshold = erc20.totalSupply.fraction(_liquidityThresholdPercentage);

    _setupUniswap(_v2RouterAddress, _basePairAddress);

    erc20.swapHelper = address(new SwapHelper());

    erc20.users[msg.sender].balance = erc20.totalSupply;
    emit Transfer(address(0), msg.sender, erc20.totalSupply);
  }

  function _setupUniswap(address _routerAddress, address _basePairAddress) private {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    erc20.uniswapV2Router = IUniswapV2Router02(_routerAddress);

    // create a uniswap pair for this new token
    erc20.uniswapV2Pair = IUniswapV2Factory(erc20.uniswapV2Router.factory())
      .createPair(address(this), _basePairAddress);

    erc20.basePair = IERC20(_basePairAddress);

    _setAutomatedMarketMakerPair(erc20.uniswapV2Pair, true);
  }

  function name() public view override returns(string memory) {
    return ERC20BaseStorage.getStorage().name;
  }

  function symbol() public view override returns(string memory) {
    return ERC20BaseStorage.getStorage().symbol;
  }

  function decimals() public view override returns(uint8) {
    return ERC20BaseStorage.getStorage().decimals;
  }

  function totalSupply() public view override returns(uint256) {
    return ERC20BaseStorage.getStorage().totalSupply;
  }

  function balanceOf(address account) public view override returns(uint256) {
    return ERC20BaseStorage.getStorage().users[account].balance;
  }

  function allowance(address owner, address spender) public view override returns(uint256) {
    return ERC20BaseStorage.getStorage().users[owner].allowances[spender];
  }

  function getTransactionFees(address sender, address recipient)
    public
    view
    override
    returns(
      bytes32 feeType,
      uint256 totalFee,
      uint256 liquidityFee,
      uint256 platformFee
    )
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    feeType = TX_FREE;

    if(
      !isExcludedFrom(UserFeatures.FEATURE_FEE, sender)
        && !isExcludedFrom(UserFeatures.FEATURE_FEE, recipient)
    ) {
      if(erc20.automatedMarketMakerPairs[sender]) {
        feeType = TX_BUY;
      } else if(erc20.automatedMarketMakerPairs[recipient]) {
        if((block.number - thisToken.initialLiquidityBlockNumber) < thisToken.launchBlockAmount) {
          feeType = TX_LAUNCH_PROTECTION;

          return (
            feeType,
            erc20.fees[feeType].totalFee,
            erc20.fees[feeType].liquidityFee,
            erc20.fees[feeType].platformFee
          );
        } else {
          feeType = TX_SELL;
        }
      } else {
        feeType = TX_TRANSFER;
      }
    }

    return (
      feeType,
      erc20.fees[feeType].totalFee,
      erc20.fees[feeType].liquidityFee,
      erc20.fees[feeType].platformFee
    );
  }

  function getCollectedFees() external view override returns(
    uint256 totalFee,
    uint256 liquidityFee,
    uint256 platformFee
  ) {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    ERC20BaseStorage.Fee storage collectedFees = erc20.collectedFees;

    return (
      collectedFees.totalFee,
      collectedFees.liquidityFee,
      collectedFees.platformFee
    );
  }

  /* -===== MUTATIVE FUNCTIONS ------ */

  function approve(address spender, uint256 amount) public override returns(bool) {
    _approve(msg.sender, spender, amount);
    return true;
  }

  function transfer(address recipient, uint256 amount) public override returns(bool) {
    _transfer(msg.sender, recipient, amount);
    return true;
  }

  function transferFrom(address sender, address recipient, uint256 amount)
    public
    override
    returns(bool)
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    _transfer(sender, recipient, amount);
    _approve(sender, msg.sender, erc20.users[sender].allowances[msg.sender] - amount);

    return true;
  }

  function changeFees(
    bytes32 txType,
    uint256 liquidityFee,
    uint256 platformFee
  )
    public
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    if(txType == TX_BUY) {
      require(liquidityFee <= 3000);
      require(platformFee <= 3000);
    }

    if(txType == TX_SELL) {
      require(liquidityFee <= 3000);
      require(platformFee <= 3000);
    }

    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    erc20.fees[txType].liquidityFee = liquidityFee;
    erc20.fees[txType].platformFee = platformFee;

    erc20.fees[txType].totalFee = (liquidityFee + platformFee);
  }

  function toggleLiquidityModule(bool _enabled)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    erc20.liquidityModuleEnabled = _enabled;
    emit LiquidityModuleToggled(_enabled);
  }

  function setTokenReserveThreshold(uint256 _liquidityThresholdPercentage)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    erc20.tokenReserveThreshold = erc20.totalSupply.fraction(_liquidityThresholdPercentage);
  }

  function _setAutomatedMarketMakerPair(address pairAddress, bool isAMM) internal {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    if(!isAMM) {
      require(pairAddress != erc20.uniswapV2Pair, 'UNISWAP_PAIR');
    }

    erc20.automatedMarketMakerPairs[pairAddress] = isAMM;
    emit SetAutomatedMarketMakerPair(pairAddress, isAMM);
  }

  function _approve(address owner, address spender, uint256 amount) private {
    require(owner != address(0), 'FROM_ZERO_ADDRESS');
    require(spender != address(0), 'TO_ZERO_ADDRESS');

    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    erc20.users[owner].allowances[spender] = amount;

    emit Approval(owner, spender, amount);
  }

  function _transfer(address sender, address recipient, uint256 amount) private {
    require(sender != address(0), 'FROM_ZERO_ADDRESS');
    require(recipient != address(0), 'TO_ZERO_ADDRESS');
    require(amount > 0, 'ZERO_AMOUNT');

    _processFees(sender);
    _beforeTokenTransfer(sender, recipient, amount);

    (,
      uint256 totalFee,
      uint256 platformFee,
      uint256 liquidityFee
    ) = getTransactionFees(sender, recipient);

    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    ERC20BaseStorage.Fee storage collectedFees = erc20.collectedFees;
    ERC20BaseStorage.User storage ownContract = erc20.users[address(this)];

    uint256 txnCollectedFees;

    if(totalFee > 0) {
      if(platformFee > 0) {
        uint256 txnBridgeTheGapFee = amount.fraction(platformFee);

        collectedFees.platformFee += txnBridgeTheGapFee;
        collectedFees.totalFee += txnBridgeTheGapFee;
        txnCollectedFees += txnBridgeTheGapFee;
      }

      if(liquidityFee > 0) {
        uint256 txnLiquidityFee = amount.fraction(liquidityFee);

        collectedFees.liquidityFee += txnLiquidityFee;
        collectedFees.totalFee += txnLiquidityFee;
        txnCollectedFees += txnLiquidityFee;
      }

      ownContract.balance += txnCollectedFees;
      emit Transfer(sender, address(this), txnCollectedFees);
    }

    uint256 taxedAmount = amount - txnCollectedFees;

    erc20.users[sender].balance -= amount;
    erc20.users[recipient].balance += taxedAmount;

    emit Transfer(sender, recipient, taxedAmount);

    _afterTokenTransfer(sender, recipient, amount, taxedAmount);
  }

  function _processLiquidity(uint256 amountInTokens, uint256 amountInBasePair) private {
    if(amountInTokens == 0 || amountInBasePair == 0) {
      return;
    }

    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    // approve token transfer
    _approve(address(this), address(erc20.uniswapV2Router), amountInTokens);
    erc20.basePair.approve(address(erc20.uniswapV2Router), amountInBasePair);

    // add the liquidity
    erc20.uniswapV2Router.addLiquidity(
      address(this),
      address(erc20.basePair),
      amountInTokens,
      amountInBasePair,
      0, // slippage is unavoidable
      0, // slippage is unavoidable
      erc20.liquidityWallet,
      block.timestamp
    );

    emit AddLiquidity(amountInTokens, amountInBasePair);
  }

  function _processBridgeTheGapFee(uint256 amountInBasePair) private {
    if(amountInBasePair == 0) {
      return;
    }

    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    erc20.basePair.safeTransfer(erc20.platformWallet, amountInBasePair);
  }

  function _processFees(address sender) private {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    uint256 pendingFees = Math.min(
      erc20.collectedFees.totalFee,
      thisToken.maxTransactionAmount
    );

    if(
      (pendingFees >= erc20.tokenReserveThreshold)
        && !erc20.inSwapAndLiquify
        && sender != erc20.uniswapV2Pair
        && erc20.liquidityModuleEnabled
        && !hasRole(LIQUIFY_BYPASSER_ROLE, sender)
    ) {
      erc20.inSwapAndLiquify = true;

      FeeProcessingQueue memory allSwaps;

      {
        allSwaps.platformRate = erc20
          .collectedFees
          .platformFee
          .getRate(erc20.collectedFees.totalFee);

        allSwaps.platformSwapAmount = pendingFees
          .fromRate(allSwaps.platformRate);

        erc20.collectedFees.platformFee -= allSwaps.platformSwapAmount;
      }

      {
        allSwaps.liquidityRate = erc20
          .collectedFees
          .liquidityFee
          .getRate(erc20.collectedFees.totalFee);

        allSwaps.liquiditySwapAmount = pendingFees
          .fromRate(allSwaps.liquidityRate);

        allSwaps.liquidityAddAmount = allSwaps.liquiditySwapAmount / 2;
        allSwaps.liquiditySwapAmount -= allSwaps.liquidityAddAmount;

        erc20.collectedFees.liquidityFee -= (allSwaps.liquidityAddAmount + allSwaps.liquiditySwapAmount);
      }

      uint256 amountToSwap = allSwaps.platformSwapAmount
        + allSwaps.liquiditySwapAmount;

      erc20.collectedFees.totalFee -= allSwaps.liquidityAddAmount
        + allSwaps.liquiditySwapAmount
        + allSwaps.platformSwapAmount;

      if(amountToSwap > 0) {
        uint256 deltaBasePair = _swapTokensReturningDelta(
          address(this),
          address(erc20.basePair),
          amountToSwap
        );

        _processLiquidity(
          allSwaps.liquidityAddAmount,
          deltaBasePair - deltaBasePair.fromRate(allSwaps.platformRate)
        );

        _processBridgeTheGapFee(deltaBasePair.fromRate(allSwaps.platformRate));
      }

      // dust after executing all swaps
      erc20.contractRedeemableETH = address(this).balance;
      erc20.inSwapAndLiquify = false;
    }
  }

  function _swapTokensReturningDelta(
    address inputTokenAddress,
    address outputTokenAddress,
    uint256 amountInTokens
  ) private returns(uint256) {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    address[] memory path = new address[](2);
    path[0] = inputTokenAddress;
    path[1] = outputTokenAddress;

    IERC20(inputTokenAddress)
      .approve(address(erc20.uniswapV2Router), amountInTokens);

    IERC20 outputToken = IERC20(outputTokenAddress);

    uint256 initialBalance = outputToken.balanceOf(address(this));

    // make the swap
    erc20.uniswapV2Router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
      amountInTokens,
      0, // slippage 100%
      path,
      erc20.swapHelper,
      block.timestamp
    );

    uint256 tradedAmount = outputToken.balanceOf(erc20.swapHelper);

    SwapHelper(erc20.swapHelper).approve(outputToken, tradedAmount);

    outputToken.safeTransferFrom(
      erc20.swapHelper,
      address(this),
      tradedAmount
    );

    return outputToken.balanceOf(address(this)) - initialBalance;
  }

  function _beforeTokenTransfer(
    address sender,
    address recipient,
    uint256 amount
  ) internal virtual {}

  function _afterTokenTransfer(
    address sender,
    address recipient,
    uint256 sentAmount,
    uint256 receivedAmount
  ) internal virtual {}
}

// File: @openzeppelin/contracts/security/ReentrancyGuard.sol

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// File: contracts/ThisToken.sol

pragma solidity 0.8.19;

contract ThisToken is
  IThisToken,
  AccessControlEnumerable,
  ReentrancyGuard,
  UserFeatures,
  ERC20Base
{
  using Percentages for uint256;
  using SafeERC20 for IERC20;

  bytes32 internal constant SNIPER_ROLE = keccak256('SNIPER_ROLE');
  bytes32 internal constant LIQUIDITY_MANAGER_ROLE = keccak256('LIQUIDITY_MANAGER_ROLE');

  constructor(
    string memory _name,
    string memory _symbol,

    uint256 _supply,
    uint256 _maxTxnPercentage,
    uint256 _maxBalancePercentage,
    uint256 _liquidityThresholdPercentage,

    uint256[2] memory _buyFees,
    uint256[2] memory _sellFees,

    address[3] memory _addresses,

    address _v2Router
  ) ERC20Base(
    _name,
    _symbol,
    _supply,
    _liquidityThresholdPercentage,
    _v2Router,
    _addresses[0]
  ) {
    ThisTokenStorage.initializeDefaults();
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    _setupRole(LIQUIDITY_MANAGER_ROLE, msg.sender);

    erc20.platformWallet = _addresses[1];
    erc20.liquidityWallet = _addresses[2];

    _setupExclusions();

    changeFees(ERC20Base.TX_BUY, _buyFees[0], _buyFees[1]);
    changeFees(ERC20Base.TX_SELL, _sellFees[0], _sellFees[1]);

    setMaxTransactionPercentage(_maxTxnPercentage);
    setMaxBalancePercentage(_maxBalancePercentage);
  }

  /* -===== MUTATIVE FUNCTIONS ------ */

  function toggleLaunchProtectionModule(bool enabled)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ThisTokenStorage.getStorage().launchProtectionModuleEnabled = enabled;
  }

  function enableTrading()
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ThisTokenStorage.getStorage().tradingEnabled = true;
  }

  function setMaxTransactionPercentage(uint256 maxTransactionPercentage)
    public
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    require(maxTransactionPercentage >= 50); // minimum 0.05%

    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();
    thisToken.maxTransactionAmount = totalSupply().fraction(maxTransactionPercentage);
  }

  function setMaxBalancePercentage(uint256 maxBalancePercentage)
    public
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    require(maxBalancePercentage >= 50); // minimum 0.05%

    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();
    thisToken.maxBalanceAmount = totalSupply().fraction(maxBalancePercentage);
  }

  function setSwapAndLiquifyEnabled(bool _enabled) external {
    toggleSwapAndLiquifyModule(_enabled);
  }

  function toggleSwapAndLiquifyModule(bool enabled)
    public
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ERC20BaseStorage.getStorage().liquidityModuleEnabled = enabled;
    emit SwapAndLiquifyModuleToggle(enabled);
  }

  function setAutomatedMarketMakerPair(address pairAddress, bool isAMM)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    _setAutomatedMarketMakerPair(pairAddress, isAMM);
  }

  function setBridgeTheGapWallet(address newWallet)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    erc20.platformWallet = newWallet;
  }

  function setLiquidityWallet(address newWallet)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    erc20.liquidityWallet = newWallet;
  }

  function redeemLockedETH(address recipient)
    external
    override
    nonReentrant
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    require(recipient != address(0), 'ZERO_ADDRESS');
    require(erc20.contractRedeemableETH > 0 || erc20.contractRedeemableBasePair > 0, 'ZERO_BALANCE');

    uint256 amountInETH = erc20.contractRedeemableETH;
    uint256 amountInBasePair = erc20.contractRedeemableBasePair;

    erc20.contractRedeemableETH = 0;
    erc20.contractRedeemableBasePair = 0;

    if(amountInETH > 0) {
      (bool success,) = payable(recipient).call{value: amountInETH}('');

      if(!success) {
        revert();
      }
    }

    if(amountInBasePair > 0) {
      erc20.basePair.safeTransfer(recipient, amountInBasePair);
    }
  }

  // withdraw any tokens that are not supposed to be inside this contract.
  function redeemLockedTokens(address _recipient, address _token)
    external
    override
    onlyRole(DEFAULT_ADMIN_ROLE)
  {
    require(_token != address(this), 'REDEEM_OWN_TOKEN');

    IERC20 token = IERC20(_token);
    token.transfer(_recipient, token.balanceOf(address(this)));
  }

  function _setupExclusions() private {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();

    bytes32[] memory excludeAll = new bytes32[](4);

    excludeAll[0] = FEATURE_FEE;
    excludeAll[1] = FEATURE_MAXTX;
    excludeAll[2] = FEATURE_MAXBALANCE;

    setupUserExclusions(msg.sender, excludeAll);
    setupUserExclusions(address(this), excludeAll);
    setupUserExclusions(erc20.platformWallet, excludeAll);
    setupUserExclusions(erc20.liquidityWallet, excludeAll);
    setupUserExclusions(erc20.swapHelper, excludeAll);

    bytes32[] memory excludeAMM = new bytes32[](2);

    excludeAMM[1] = FEATURE_MAXBALANCE;

    setupUserExclusions(erc20.uniswapV2Pair, excludeAMM);
  }

  function _ensureWalletLimit(address recipient, uint256 amount) private view {
    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    if(thisToken.maxBalanceEnabled) {
      require(
        ((balanceOf(recipient) + amount) <= thisToken.maxBalanceAmount) || isExcludedFrom(FEATURE_MAXBALANCE, recipient),
        'MAX_WALLET_EXCEEDED'
      );
    }
  }

  function _ensureTransactionLimit(address sender, address recipient, uint256 amount) private view {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    if(erc20.automatedMarketMakerPairs[sender]) {
      require(amount <= thisToken.maxTransactionAmount || isExcludedFrom(FEATURE_MAXTX, recipient), 'TX_LIMIT_EXCEEDED');
    } else {
      require(amount <= thisToken.maxTransactionAmount || isExcludedFrom(FEATURE_MAXTX, sender), 'TX_LIMIT_EXCEEDED');
    }
  }

  function _ensureLaunchProtection(address sender, address recipient) private {
    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    // are we adding initial liquidity?
    if(!thisToken.initialLiquidityAdded) {
      _checkTransactionForInitialLiquidity(sender, recipient);
    }
  }

  function _checkTransactionForInitialLiquidity(address sender, address recipient) private {
    ERC20BaseStorage.Storage storage erc20 = ERC20BaseStorage.getStorage();
    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    require(!thisToken.initialLiquidityAdded, 'INITIAL_LIQUIDITY_ALREADY_ADDED');

    if((recipient == erc20.uniswapV2Pair) && hasRole(LIQUIDITY_MANAGER_ROLE, sender)) {
      thisToken.initialLiquidityAdded = true;
      thisToken.initialLiquidityBlockNumber = block.number;
      thisToken.tradingEnabled = true;
    }
  }

  function _beforeTokenTransfer(address sender, address recipient, uint256 amount)
    internal
    virtual
    override(ERC20Base)
  {
    super._beforeTokenTransfer(sender, recipient, amount);

    ThisTokenStorage.Storage storage thisToken = ThisTokenStorage.getStorage();

    if(!isExcludedFrom(FEATURE_FEE, sender) && !isExcludedFrom(FEATURE_FEE, recipient)) {
      require(thisToken.tradingEnabled, 'TRADING_DISABLED');
    }

    _ensureWalletLimit(recipient, amount);
    _ensureTransactionLimit(sender, recipient, amount);

    if(thisToken.launchProtectionModuleEnabled) {
      _ensureLaunchProtection(sender, recipient);
    }
  }

  function _afterTokenTransfer(address sender, address recipient, uint256 sentAmount, uint256 receivedAmount)
    internal
    virtual
    override(ERC20Base)
  {
    super._afterTokenTransfer(sender, recipient, sentAmount, receivedAmount);
  }

  receive() external payable {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"uint256","name":"_maxTxnPercentage","type":"uint256"},{"internalType":"uint256","name":"_maxBalancePercentage","type":"uint256"},{"internalType":"uint256","name":"_liquidityThresholdPercentage","type":"uint256"},{"internalType":"uint256[2]","name":"_buyFees","type":"uint256[2]"},{"internalType":"uint256[2]","name":"_sellFees","type":"uint256[2]"},{"internalType":"address[3]","name":"_addresses","type":"address[3]"},{"internalType":"address","name":"_v2Router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountInTokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountInWETH","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"LiquidityModuleToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pairAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"isAMM","type":"bool"}],"name":"SetAutomatedMarketMakerPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SwapAndLiquifyModuleToggle","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"txType","type":"bytes32"},{"internalType":"uint256","name":"liquidityFee","type":"uint256"},{"internalType":"uint256","name":"platformFee","type":"uint256"}],"name":"changeFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableTrading","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCollectedFees","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"},{"internalType":"uint256","name":"liquidityFee","type":"uint256"},{"internalType":"uint256","name":"platformFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"getTransactionFees","outputs":[{"internalType":"bytes32","name":"feeType","type":"bytes32"},{"internalType":"uint256","name":"totalFee","type":"uint256"},{"internalType":"uint256","name":"liquidityFee","type":"uint256"},{"internalType":"uint256","name":"platformFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feature","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"isExcludedFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"redeemLockedETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"redeemLockedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pairAddress","type":"address"},{"internalType":"bool","name":"isAMM","type":"bool"}],"name":"setAutomatedMarketMakerPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWallet","type":"address"}],"name":"setBridgeTheGapWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWallet","type":"address"}],"name":"setLiquidityWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxBalancePercentage","type":"uint256"}],"name":"setMaxBalancePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxTransactionPercentage","type":"uint256"}],"name":"setMaxTransactionPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setSwapAndLiquifyEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_liquidityThresholdPercentage","type":"uint256"}],"name":"setTokenReserveThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"items","type":"bytes32[]"}],"name":"setupUserExclusions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"items","type":"bytes32[]"}],"name":"setupUserInclusions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"toggleLaunchProtectionModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"toggleLiquidityModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"toggleSwapAndLiquifyModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b5060405162005afd38038062005afd83398101604081905262000034916200106b565b815160016002557f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c9805460ff191660121790557f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d8805461ff0019166101001790556040805160608101825261afc8815261abe060208281019182526103e89383019384527fea54d35234a268da5de307f513b1064e5a4d637cfef76180b0dbb003c2c6ff8960005260008051602062005a3d833981519152905290517f784648c6a60c405e26e9e455afe3a6555d9e130c279c20e2584bc02459767b6c55517f784648c6a60c405e26e9e455afe3a6555d9e130c279c20e2584bc02459767b6d55517f784648c6a60c405e26e9e455afe3a6555d9e130c279c20e2584bc02459767b6e558a908a908a908890859060008051602062005a1d833981519152806200017f8882620011f0565b5060018101620001908782620011f0565b5060028101805460ff19166012908117909155620001b090600a620013cf565b620001bc9086620013dd565b60038201819055620001cf908562000390565b6012820155620001e083836200042d565b604051620001ee9062000e8b565b604051809103906000f0801580156200020b573d6000803e3d6000fd5b506013820180546001600160a01b0319166001600160a01b03929092169190911790556003810154336000818152600484016020908152604080832085905551938452919290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a350505050505050620002946200059c60201b60201c565b60008051602062005a1d833981519152620002b160003362000632565b620002dd7f77e60b99a50d27fb027f6912a507d956105b4148adab27a86d235c8bcca8fa2f3362000632565b6020830151600a820180546001600160a01b039283166001600160a01b0319918216179091556040850151600b840180549190931691161790556200032162000658565b8451620003489060008051602062005add833981519152908760015b602002015162000816565b8351620003699060008051602062005abd833981519152908660016200033d565b6200037488620008f2565b6200037f876200094d565b505050505050505050505062001516565b6000620186a0821115620003e05760405162461bcd60e51b8152602060048201526012602482015271494e56414c49445f50455243454e5441474560701b60448201526064015b60405180910390fd5b620003f7670de0b6b3a7640000620186a0620013dd565b670de0b6b3a76400006200040c8486620013dd565b620004189190620013dd565b620004249190620013f7565b90505b92915050565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d380546001600160a01b0319166001600160a01b0384169081179091556040805163c45a015560e01b8152905160008051602062005a1d833981519152929163c45a01559160048083019260209291908290030181865afa158015620004b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004dd91906200141a565b6040516364e329cb60e11b81523060048201526001600160a01b038481166024830152919091169063c9c65396906044016020604051808303816000875af11580156200052e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200055491906200141a565b600d820180546001600160a01b039283166001600160a01b03199182168117909255600e84018054938616939091169290921790915562000597906001620009a1565b505050565b60008051602062005a9d833981519152805462ffffff191660019081179091557f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec385805460ff1916909117905560237f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3865560007f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38755565b6200063e828262000a6e565b600082815260016020526040902062000597908262000a7e565b60408051600480825260a0820190925260008051602062005a1d8339815191529160009190602082016080803683370190505090507f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d81600081518110620006c457620006c46200114c565b6020026020010181815250507f9371c8791e1754c08ca054e61e0f5b5d74d999eee60ddd36b3906606c1f7edc9816001815181106200070757620007076200114c565b60200260200101818152505060008051602062005a7d833981519152816002815181106200073957620007396200114c565b602090810291909101015262000750338262000a95565b6200075c308262000a95565b600a82015462000776906001600160a01b03168262000a95565b600b82015462000790906001600160a01b03168262000a95565b6013820154620007aa906001600160a01b03168262000a95565b60408051600280825260608201835260009260208301908036833701905050905060008051602062005a7d83398151915281600181518110620007f157620007f16200114c565b6020908102919091010152600d83015462000597906001600160a01b03168262000a95565b600062000824813362000ab1565b60008051602062005add83398151915284036200085b57610bb88311156200084b57600080fd5b610bb88211156200085b57600080fd5b60008051602062005abd83398151915284036200089257610bb88311156200088257600080fd5b610bb88211156200089257600080fd5b600084815260008051602062005a3d833981519152602052604090206002810184905560010182905560008051602062005a1d833981519152620008d7838562001438565b60009586526006909101602052604090942093909355505050565b600062000900813362000ab1565b60328210156200090f57600080fd5b60008051602062005a9d83398151915262000943836200093c60008051602062005a5d8339815191525490565b9062000390565b6002909101555050565b60006200095b813362000ab1565b60328210156200096a57600080fd5b60008051602062005a9d83398151915262000997836200093c60008051602062005a5d8339815191525490565b6001909101555050565b60008051602062005a1d8339815191528162000a0857600d8101546001600160a01b039081169084160362000a085760405162461bcd60e51b815260206004820152600c60248201526b2aa724a9aba0a82fa820a4a960a11b6044820152606401620003d7565b6001600160a01b0383166000818152600583016020908152604091829020805460ff19168615159081179091558251938452908301527fffa9187bf1f18bf477bd0ea1bcbb64e93b6a98132473929edfce215cd9b16fab910160405180910390a1505050565b62000a7a828262000b38565b5050565b600062000424836001600160a01b03841662000bd8565b600062000aa3813362000ab1565b620005978383600162000c2a565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000a7a5762000af06001600160a01b038216601462000cd2565b62000afd83602062000cd2565b60405160200162000b109291906200144e565b60408051601f198184030181529082905262461bcd60e51b8252620003d791600401620014c7565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000a7a576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905562000b943390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600081815260018301602052604081205462000c215750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000427565b50600062000427565b60005b825181101562000ccc576001600160a01b03841660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960205260408120845184929086908590811062000c885762000c886200114c565b6020026020010151815260200190815260200160002060006101000a81548160ff02191690831515021790555060018162000cc4919062001438565b905062000c2d565b50505050565b6060600062000ce3836002620013dd565b62000cf090600262001438565b6001600160401b0381111562000d0a5762000d0a62000e99565b6040519080825280601f01601f19166020018201604052801562000d35576020820181803683370190505b509050600360fc1b8160008151811062000d535762000d536200114c565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811062000d855762000d856200114c565b60200101906001600160f81b031916908160001a905350600062000dab846002620013dd565b62000db890600162001438565b90505b600181111562000e3a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811062000df05762000df06200114c565b1a60f81b82828151811062000e095762000e096200114c565b60200101906001600160f81b031916908160001a90535060049490941c9362000e3281620014fc565b905062000dbb565b508315620004245760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401620003d7565b61059e806200547f83390190565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000ecc57818101518382015260200162000eb2565b50506000910152565b600082601f83011262000ee757600080fd5b81516001600160401b038082111562000f045762000f0462000e99565b604051601f8301601f19908116603f0116810190828211818310171562000f2f5762000f2f62000e99565b8160405283815286602085880101111562000f4957600080fd5b62000f5c84602083016020890162000eaf565b9695505050505050565b600082601f83011262000f7857600080fd5b604080519081016001600160401b038111828210171562000f9d5762000f9d62000e99565b806040525080604084018581111562000fb557600080fd5b845b8181101562000fd157805183526020928301920162000fb7565b509195945050505050565b80516001600160a01b038116811462000ff457600080fd5b919050565b600082601f8301126200100b57600080fd5b604051606081016001600160401b038111828210171562001030576200103062000e99565b6040528060608401858111156200104657600080fd5b845b8181101562000fd1576200105c8162000fdc565b83526020928301920162001048565b6000806000806000806000806000806101c08b8d0312156200108c57600080fd5b8a516001600160401b0380821115620010a457600080fd5b620010b28e838f0162000ed5565b9b5060208d0151915080821115620010c957600080fd5b50620010d88d828e0162000ed5565b99505060408b0151975060608b0151965060808b0151955060a08b01519450620011068c60c08d0162000f66565b9350620011188c6101008d0162000f66565b92506200112a8c6101408d0162000ff9565b91506200113b6101a08c0162000fdc565b90509295989b9194979a5092959850565b634e487b7160e01b600052603260045260246000fd5b600181811c908216806200117757607f821691505b6020821081036200119857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200059757600081815260208120601f850160051c81016020861015620011c75750805b601f850160051c820191505b81811015620011e857828155600101620011d3565b505050505050565b81516001600160401b038111156200120c576200120c62000e99565b62001224816200121d845462001162565b846200119e565b602080601f8311600181146200125c5760008415620012435750858301515b600019600386901b1c1916600185901b178555620011e8565b600085815260208120601f198616915b828110156200128d578886015182559484019460019091019084016200126c565b5085821015620012ac5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111562001313578160001904821115620012f757620012f7620012bc565b808516156200130557918102915b93841c9390800290620012d7565b509250929050565b6000826200132c5750600162000427565b816200133b5750600062000427565b81600181146200135457600281146200135f576200137f565b600191505062000427565b60ff841115620013735762001373620012bc565b50506001821b62000427565b5060208310610133831016604e8410600b8410161715620013a4575081810a62000427565b620013b08383620012d2565b8060001904821115620013c757620013c7620012bc565b029392505050565b60006200042483836200131b565b8082028115828204841417620004275762000427620012bc565b6000826200141557634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156200142d57600080fd5b620004248262000fdc565b80820180821115620004275762000427620012bc565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516200148881601785016020880162000eaf565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351620014bb81602884016020880162000eaf565b01602801949350505050565b6020815260008251806020840152620014e881604085016020870162000eaf565b601f01601f19169190910160400192915050565b6000816200150e576200150e620012bc565b506000190190565b613f5980620015266000396000f3fe60806040526004361061026e5760003560e01c80637594af7811610153578063b361bbbb116100cb578063d547741f1161007f578063dce6950611610064578063dce6950614610800578063dd62ed3e14610862578063ea8d1984146108cb57600080fd5b8063d547741f14610752578063d54a8d181461077257600080fd5b8063c7a6ec12116100b0578063c7a6ec12146106d2578063c8daadac146106f2578063ca15c8731461073257600080fd5b8063b361bbbb14610692578063c49b9a80146106b257600080fd5b806395d89b41116101225780639a7a23d6116101075780639a7a23d61461063d578063a217fddf1461065d578063a9059cbb1461067257600080fd5b806395d89b411461060857806395f31dde1461061d57600080fd5b80637594af78146105575780638a8c523c146105775780639010d07c1461058c57806391d14854146105c457600080fd5b80632f2ff15d116101e657806340667d46116101b55780635af0e8441161019a5780635af0e844146104c25780636f784216146104e257806370a082311461050257600080fd5b806340667d4614610482578063533ff7ec146104a257600080fd5b80632f2ff15d146103e1578063313ce56714610401578063316ef97e1461044257806336568abe1461046257600080fd5b80631d2a77201161023d578063248a9ca311610222578063248a9ca314610371578063296f0a0c146103a15780632ae711ed146103c157600080fd5b80631d2a77201461032f57806323b872dd1461035157600080fd5b806301ffc9a71461027a57806306fdde03146102af578063095ea7b3146102d157806318160ddd146102f157600080fd5b3661027557005b600080fd5b34801561028657600080fd5b5061029a610295366004613893565b6108eb565b60405190151581526020015b60405180910390f35b3480156102bb57600080fd5b506102c4610947565b6040516102a691906138f9565b3480156102dd57600080fd5b5061029a6102ec366004613966565b6109f8565b3480156102fd57600080fd5b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca545b6040519081526020016102a6565b34801561033b57600080fd5b5061034f61034a3660046139bf565b610a0e565b005b34801561035d57600080fd5b5061029a61036c366004613aae565b610a2b565b34801561037d57600080fd5b5061032161038c366004613aea565b60009081526020819052604090206001015490565b3480156103ad57600080fd5b5061034f6103bc366004613b03565b610aa9565b3480156103cd57600080fd5b5061034f6103dc366004613b03565b610b0f565b3480156103ed57600080fd5b5061034f6103fc366004613b1e565b610cf8565b34801561040d57600080fd5b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c95460405160ff90911681526020016102a6565b34801561044e57600080fd5b5061034f61045d366004613b4a565b610d1a565b34801561046e57600080fd5b5061034f61047d366004613b1e565b610e30565b34801561048e57600080fd5b5061034f61049d366004613b84565b610e52565b3480156104ae57600080fd5b5061034f6104bd366004613b03565b610ee9565b3480156104ce57600080fd5b5061034f6104dd366004613aea565b610f4f565b3480156104ee57600080fd5b5061034f6104fd366004613aea565b610fc6565b34801561050e57600080fd5b5061032161051d366004613b03565b6001600160a01b031660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602052604090205490565b34801561056357600080fd5b5061034f610572366004613b84565b61102a565b34801561058357600080fd5b5061034f611069565b34801561059857600080fd5b506105ac6105a7366004613ba1565b6110c3565b6040516001600160a01b0390911681526020016102a6565b3480156105d057600080fd5b5061029a6105df366004613b1e565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561061457600080fd5b506102c46110db565b34801561062957600080fd5b5061034f610638366004613aea565b61110c565b34801561064957600080fd5b5061034f610658366004613bc3565b61117d565b34801561066957600080fd5b50610321600081565b34801561067e57600080fd5b5061029a61068d366004613966565b611193565b34801561069e57600080fd5b5061034f6106ad366004613bfa565b6111a0565b3480156106be57600080fd5b5061034f6106cd366004613b84565b61131f565b3480156106de57600080fd5b5061034f6106ed3660046139bf565b61132b565b3480156106fe57600080fd5b5061071261070d366004613bfa565b611343565b6040805194855260208501939093529183015260608201526080016102a6565b34801561073e57600080fd5b5061032161074d366004613aea565b6115df565b34801561075e57600080fd5b5061034f61076d366004613b1e565b6115f6565b34801561077e57600080fd5b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ce547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d0547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cf54604080519384526020840192909252908201526060016102a6565b34801561080c57600080fd5b5061029a61081b366004613b1e565b6001600160a01b031660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960209081526040808320938352929052205460ff1690565b34801561086e57600080fd5b5061032161087d366004613bfa565b6001600160a01b0391821660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602090815260408083209390941682526001909201909152205490565b3480156108d757600080fd5b5061034f6108e6366004613b84565b611600565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806109415750610941826116bc565b92915050565b60607f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7805461097590613c24565b80601f01602080910402602001604051908101604052809291908181526020018280546109a190613c24565b80156109ee5780601f106109c3576101008083540402835291602001916109ee565b820191906000526020600020905b8154815290600101906020018083116109d157829003601f168201915b5050505050905090565b6000610a05338484611753565b50600192915050565b6000610a1a81336118a8565b610a2683836000611948565b505050565b60007f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7610a598585856119e9565b6001600160a01b0385166000908152600482016020908152604080832033808552600190910190925290912054610a9c918791610a97908790613ca6565b611753565b60019150505b9392505050565b6000610ab581336118a8565b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6002805403610b655760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600280556000610b7581336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c76001600160a01b038316610bec5760405162461bcd60e51b815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152606401610b5c565b600081600f01541180610c03575060008160100154115b610c4f5760405162461bcd60e51b815260206004820152600c60248201527f5a45524f5f42414c414e434500000000000000000000000000000000000000006044820152606401610b5c565b600f81018054601083018054600093849055929055908115610ccd576000856001600160a01b03168360405160006040518083038185875af1925050503d8060008114610cb8576040519150601f19603f3d011682016040523d82523d6000602084013e610cbd565b606091505b5050905080610ccb57600080fd5b505b8015610cec57600e830154610cec906001600160a01b03168683611d33565b50506001600255505050565b610d028282611dfa565b6000828152600160205260409020610a269082611e20565b6000610d2681336118a8565b7f86ff79e1b5adb224d25415c777ccd653d71e2187f2e9ec212c12480572d79ef78403610d6b57610bb8831115610d5c57600080fd5b610bb8821115610d6b57600080fd5b7f600a2b12f2bedfdadd0fde1768f2416392cb05081ac1ae7ca466d1150ee0862b8403610db057610bb8831115610da157600080fd5b610bb8821115610db057600080fd5b60008481527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cd60205260409020600281018490556001018290557f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7610e158385613cb9565b60009586526006909101602052604090942093909355505050565b610e3a8282611e35565b6000828152600160205260409020610a269082611ebd565b6000610e5e81336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101008415159081029190911790915560408051918252517f6bcabd360224c151477bb16b5a2ad6271f8c1f1345575b8d4490e046b9b96fc39181900360200190a15050565b6000610ef581336118a8565b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000610f5b81336118a8565b6032821015610f6957600080fd5b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec382610fbc83610fb67f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca5490565b90611ed2565b6001909101555050565b6000610fd281336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7906110209084611ed2565b6012909101555050565b600061103681336118a8565b507f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec385805460ff1916911515919091179055565b600061107581336118a8565b507f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b6000828152600160205260408120610aa29083611f63565b60607f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7600101805461097590613c24565b600061111881336118a8565b603282101561112657600080fd5b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38261117383610fb67f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca5490565b6002909101555050565b600061118981336118a8565b610a268383611f6f565b6000610a053384846119e9565b60006111ac81336118a8565b306001600160a01b038316036112045760405162461bcd60e51b815260206004820152601060248201527f52454445454d5f4f574e5f544f4b454e000000000000000000000000000000006044820152606401610b5c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282906001600160a01b0382169063a9059cbb90869083906370a0823190602401602060405180830381865afa15801561126d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112919190613ccc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156112f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113189190613ce5565b5050505050565b61132881610e52565b50565b600061133781336118a8565b610a2683836001611948565b7f54a61fc1270c90ad1c522bb0b76231a89910caa36c59e8fe68fafadaec70220c600080807f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c77f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3826114167f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d896001600160a01b031660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960209081526040808320938352929052205460ff1690565b15801561148657506001600160a01b03871660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d845290915290205460ff16155b156115ae576001600160a01b038816600090815260058301602052604090205460ff16156114d6577f86ff79e1b5adb224d25415c777ccd653d71e2187f2e9ec212c12480572d79ef795506115ae565b6001600160a01b038716600090815260058301602052604090205460ff161561158a576004810154600582015461150d9043613ca6565b101561156257507fea54d35234a268da5de307f513b1064e5a4d637cfef76180b0dbb003c2c6ff89600081815260069092016020526040909120805460028201546001909201549296509450925090506115d6565b7f600a2b12f2bedfdadd0fde1768f2416392cb05081ac1ae7ca466d1150ee0862b95506115ae565b7f5276e5bdffc77c7451e31f8f5537312e9d19da001480f9e0395a06c9c870b47e95505b5060008581526006909101602052604090208054600282015460019092015490945090925090505b92959194509250565b600081815260016020526040812061094190612053565b610e3a828261205d565b600061160c81336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100841515908102919091179091556040519081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7907f90b6a5dc00b3a619a544f08e22e2fd82d67cccf7ef76f473018e53551a6a1e8e906020015b60405180910390a1505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061094157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610941565b6001600160a01b0383166117a95760405162461bcd60e51b815260206004820152601160248201527f46524f4d5f5a45524f5f414444524553530000000000000000000000000000006044820152606401610b5c565b6001600160a01b0382166117ff5760405162461bcd60e51b815260206004820152600f60248201527f544f5f5a45524f5f4144445245535300000000000000000000000000000000006044820152606401610b5c565b6001600160a01b0383811660008181527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602090815260408083209487168084526001909501825291829020859055815185815291517f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c79493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92592908290030190a350505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611944576118e4816001600160a01b03166014612083565b6118ef836020612083565b604051602001611900929190613d02565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905262461bcd60e51b8252610b5c916004016138f9565b5050565b60005b82518110156119e3576001600160a01b03841660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a796020526040812084518492908690859081106119a2576119a2613d83565b6020026020010151815260200190815260200160002060006101000a81548160ff0219169083151502179055506001816119dc9190613cb9565b905061194b565b50505050565b6001600160a01b038316611a3f5760405162461bcd60e51b815260206004820152601160248201527f46524f4d5f5a45524f5f414444524553530000000000000000000000000000006044820152606401610b5c565b6001600160a01b038216611a955760405162461bcd60e51b815260206004820152600f60248201527f544f5f5a45524f5f4144445245535300000000000000000000000000000000006044820152606401610b5c565b60008111611ae55760405162461bcd60e51b815260206004820152600b60248201527f5a45524f5f414d4f554e540000000000000000000000000000000000000000006044820152606401610b5c565b611aee836122ac565b611af98383836125bb565b6000806000611b088686611343565b935093509350506000611b387f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c790565b30600090815260048201602052604081209192506007830191908615611c5c578515611bad576000611b6a8988611ed2565b905080846001016000828254611b809190613cb9565b9091555050835481908590600090611b99908490613cb9565b90915550611ba990508183613cb9565b9150505b8415611c02576000611bbf8987611ed2565b905080846002016000828254611bd59190613cb9565b9091555050835481908590600090611bee908490613cb9565b90915550611bfe90508183613cb9565b9150505b80826000016000828254611c169190613cb9565b909155505060405181815230906001600160a01b038c16907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b6000611c68828a613ca6565b6001600160a01b038c166000908152600487016020526040812080549293508b92909190611c97908490613ca6565b90915550506001600160a01b038a16600090815260048601602052604081208054839290611cc6908490613cb9565b92505081905550896001600160a01b03168b6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611d1291815260200190565b60405180910390a3611d268b8b8b8461273f565b5050505050505050505050565b6040516001600160a01b038316602482015260448101829052610a269084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612744565b600082815260208190526040902060010154611e1681336118a8565b610a268383612829565b6000610aa2836001600160a01b0384166128c7565b6001600160a01b0381163314611eb35760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610b5c565b6119448282612916565b6000610aa2836001600160a01b038416612995565b6000620186a0821115611f275760405162461bcd60e51b815260206004820152601260248201527f494e56414c49445f50455243454e5441474500000000000000000000000000006044820152606401610b5c565b611f3c670de0b6b3a7640000620186a0613db2565b670de0b6b3a7640000611f4f8486613db2565b611f599190613db2565b610aa29190613dc9565b6000610aa28383612a82565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c781611ff557600d8101546001600160a01b0390811690841603611ff55760405162461bcd60e51b815260206004820152600c60248201527f554e49535741505f5041495200000000000000000000000000000000000000006044820152606401610b5c565b6001600160a01b0383166000818152600583016020908152604091829020805460ff19168615159081179091558251938452908301527fffa9187bf1f18bf477bd0ea1bcbb64e93b6a98132473929edfce215cd9b16fab91016116af565b6000610941825490565b60008281526020819052604090206001015461207981336118a8565b610a268383612916565b60606000612092836002613db2565b61209d906002613cb9565b67ffffffffffffffff8111156120b5576120b5613990565b6040519080825280601f01601f1916602001820160405280156120df576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061211657612116613d83565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061217957612179613d83565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006121b5846002613db2565b6121c0906001613cb9565b90505b600181111561225d577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061220157612201613d83565b1a60f81b82828151811061221757612217613d83565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361225681613e04565b90506121c3565b508315610aa25760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b5c565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ce547f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec384547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7917f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3829160009161234091612b23565b90508260120154811015801561235b5750601183015460ff16155b80156123775750600d8301546001600160a01b03858116911614155b801561238c57506011830154610100900460ff165b80156123d057506001600160a01b03841660009081527ff5df84ad4d78830ee1c523fb749c590ca6c847f665d9a7a6e01ebd5b61f6fc82602052604090205460ff16155b156119e35760118301805460ff191660011790556040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526007840154600885015461242991612b39565b6020820181905261243b908390612b5e565b60408201819052600885018054600090612456908490613ca6565b90915550506007840154600985015461246e91612b39565b60608201819052612480908390612b5e565b6080820181905261249390600290613dc9565b60a082018190526080820180516124ab908390613ca6565b905250608081015160a08201516124c29190613cb9565b6009850180546000906124d6908490613ca6565b9091555050608081015160408201516000916124f191613cb9565b9050816040015182608001518360a0015161250c9190613cb9565b6125169190613cb9565b60078601805460009061252a908490613ca6565b909155505080156125a357600e8501546000906125529030906001600160a01b031684612b73565b90506125828360a00151612573856020015184612b5e90919063ffffffff16565b61257d9084613ca6565b612f7c565b6125a161259c846020015183612b5e90919063ffffffff16565b61317e565b505b505047600f8401555050601101805460ff1916905550565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3826126487f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d856001600160a01b031660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960209081526040808320938352929052205460ff1690565b1580156126b857506001600160a01b03831660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d845290915290205460ff16155b15612713578054610100900460ff166127135760405162461bcd60e51b815260206004820152601060248201527f54524144494e475f44495341424c4544000000000000000000000000000000006044820152606401610b5c565b61271d8383613206565b612728848484613341565b600381015460ff16156119e3576119e3848461354c565b6119e3565b6000612799826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135869092919063ffffffff16565b805190915015610a2657808060200190518101906127b79190613ce5565b610a265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b5c565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611944576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556128833390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600081815260018301602052604081205461290e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610941565b506000610941565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615611944576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008181526001830160205260408120548015612a785760006129b9600183613ca6565b85549091506000906129cd90600190613ca6565b905060008660000182815481106129e6576129e6613d83565b9060005260206000200154905080876000018481548110612a0957612a09613d83565b600091825260208083209091019290925582815260018901909152604090208490558654879080612a3c57612a3c613e39565b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610941565b6000915050610941565b81546000908210612afb5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60448201527f64730000000000000000000000000000000000000000000000000000000000006064820152608401610b5c565b826000018281548110612b1057612b10613d83565b9060005260206000200154905092915050565b6000818310612b325781610aa2565b5090919050565b600081600003612b4b57506000610941565b81611f59670de0b6b3a764000085613db2565b6000670de0b6b3a7640000611f598385613db2565b6040805160028082526060820183526000927f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c792849290916020830190803683370190505090508581600081518110612bce57612bce613d83565b60200260200101906001600160a01b031690816001600160a01b0316815250508481600181518110612c0257612c02613d83565b6001600160a01b039283166020918202929092010152600c8301546040517f095ea7b30000000000000000000000000000000000000000000000000000000081529082166004820152602481018690529087169063095ea7b3906044016020604051808303816000875af1158015612c7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca29190613ce5565b506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015285906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612d05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d299190613ccc565b600c85015460138601546040517f5c11d7950000000000000000000000000000000000000000000000000000000081529293506001600160a01b0391821692635c11d79592612d85928b926000928a9216904290600401613e68565b600060405180830381600087803b158015612d9f57600080fd5b505af1158015612db3573d6000803e3d6000fd5b5050505060138401546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000918416906370a0823190602401602060405180830381865afa158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e429190613ccc565b60138601546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820184905292935091169063095ea7b390604401600060405180830381600087803b158015612ead57600080fd5b505af1158015612ec1573d6000803e3d6000fd5b5050506013860154612ee291506001600160a01b038581169116308461359d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282906001600160a01b038516906370a0823190602401602060405180830381865afa158015612f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f659190613ccc565b612f6f9190613ca6565b9998505050505050505050565b811580612f87575080155b15612f90575050565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d3547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c790612fe99030906001600160a01b031685611753565b600e810154600c8201546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526024810185905291169063095ea7b3906044016020604051808303816000875af115801561305b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307f9190613ce5565b50600c810154600e820154600b8301546040517fe8e337000000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039283166024820152604481018790526064810186905260006084820181905260a482015290821660c48201524260e482015291169063e8e3370090610104016060604051808303816000875af1158015613121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131459190613ed9565b505060408051858152602081018590527fcb1652de9aeec38545fc281847b3dbfc89aab56dfa907b1ab68466f602c36fb49250016116af565b806000036131895750565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d1547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d5547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c791611944916001600160a01b03908116911684611d33565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38280546301000000900460ff1615610a265780600101548261327c856001600160a01b031660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602052604090205490565b6132869190613cb9565b1115806132f557506001600160a01b03831660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f3b60ce0b93c245c9380528a68af18188f1da33fcb86fc7f01e50bb31d116159a845290915290205460ff165b610a265760405162461bcd60e51b815260206004820152601360248201527f4d41585f57414c4c45545f4558434545444544000000000000000000000000006044820152606401610b5c565b6001600160a01b03831660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cc60205260409020547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7907f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3829060ff161561348b5780600201548311158061343a57506001600160a01b03841660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f9371c8791e1754c08ca054e61e0f5b5d74d999eee60ddd36b3906606c1f7edc9845290915290205460ff165b6134865760405162461bcd60e51b815260206004820152601160248201527f54585f4c494d49545f45584345454445440000000000000000000000000000006044820152606401610b5c565b611318565b80600201548311158061350057506001600160a01b03851660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f9371c8791e1754c08ca054e61e0f5b5d74d999eee60ddd36b3906606c1f7edc9845290915290205460ff165b6113185760405162461bcd60e51b815260206004820152601160248201527f54585f4c494d49545f45584345454445440000000000000000000000000000006044820152606401610b5c565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec382805462010000900460ff16610a2657610a2683836135ee565b6060613595848460008561371b565b949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526119e39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611d78565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38280547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7919062010000900460ff161561368a5760405162461bcd60e51b815260206004820152601f60248201527f494e495449414c5f4c49515549444954595f414c52454144595f4144444544006044820152606401610b5c565b600d8201546001600160a01b0384811691161480156136e057506001600160a01b03841660009081527fb8a5653c31e8e07e8ef5c22c947cfb9ffb7305e1fa1930db175624824a230ddf602052604090205460ff165b156119e35780544360058301557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff1662010100179055505050565b6060824710156137935760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b5c565b843b6137e15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b5c565b600080866001600160a01b031685876040516137fd9190613f07565b60006040518083038185875af1925050503d806000811461383a576040519150601f19603f3d011682016040523d82523d6000602084013e61383f565b606091505b509150915061384f82828661385a565b979650505050505050565b60608315613869575081610aa2565b8251156138795782518084602001fd5b8160405162461bcd60e51b8152600401610b5c91906138f9565b6000602082840312156138a557600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610aa257600080fd5b60005b838110156138f05781810151838201526020016138d8565b50506000910152565b60208152600082518060208401526139188160408501602087016138d5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b80356001600160a01b038116811461396157600080fd5b919050565b6000806040838503121561397957600080fd5b6139828361394a565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156139d257600080fd5b6139db8361394a565b915060208084013567ffffffffffffffff808211156139f957600080fd5b818601915086601f830112613a0d57600080fd5b813581811115613a1f57613a1f613990565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715613a6257613a62613990565b604052918252848201925083810185019189831115613a8057600080fd5b938501935b82851015613a9e57843584529385019392850192613a85565b8096505050505050509250929050565b600080600060608486031215613ac357600080fd5b613acc8461394a565b9250613ada6020850161394a565b9150604084013590509250925092565b600060208284031215613afc57600080fd5b5035919050565b600060208284031215613b1557600080fd5b610aa28261394a565b60008060408385031215613b3157600080fd5b82359150613b416020840161394a565b90509250929050565b600080600060608486031215613b5f57600080fd5b505081359360208301359350604090920135919050565b801515811461132857600080fd5b600060208284031215613b9657600080fd5b8135610aa281613b76565b60008060408385031215613bb457600080fd5b50508035926020909101359150565b60008060408385031215613bd657600080fd5b613bdf8361394a565b91506020830135613bef81613b76565b809150509250929050565b60008060408385031215613c0d57600080fd5b613c168361394a565b9150613b416020840161394a565b600181811c90821680613c3857607f821691505b602082108103613c71577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561094157610941613c77565b8082018082111561094157610941613c77565b600060208284031215613cde57600080fd5b5051919050565b600060208284031215613cf757600080fd5b8151610aa281613b76565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613d3a8160178501602088016138d5565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351613d778160288401602088016138d5565b01602801949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808202811582820484141761094157610941613c77565b600082613dff577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600081613e1357613e13613c77565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015613eb85784516001600160a01b031683529383019391830191600101613e93565b50506001600160a01b03969096166060850152505050608001529392505050565b600080600060608486031215613eee57600080fd5b8351925060208401519150604084015190509250925092565b60008251613f198184602087016138d5565b919091019291505056fea26469706673582212202efdf04f4feef6e2a06a7dd48b09fe95b14d7a61eb189004f4fb1b09664e3c9464736f6c63430008130033608060405234801561001057600080fd5b50600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35061053d806100616000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063095ea7b314610051578063715018a6146100665780638da5cb5b1461006e578063f2fde38b1461009a575b600080fd5b61006461005f366004610495565b6100ad565b005b6100646101cf565b6000546040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100646100a83660046104c1565b6102bf565b60005473ffffffffffffffffffffffffffffffffffffffff163314610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6040517f095ea7b30000000000000000000000000000000000000000000000000000000081523360048201526024810182905273ffffffffffffffffffffffffffffffffffffffff83169063095ea7b3906044016020604051808303816000875af11580156101a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101ca91906104e5565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610250576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161012a565b6000805460405173ffffffffffffffffffffffffffffffffffffffff909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610340576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161012a565b73ffffffffffffffffffffffffffffffffffffffff81166103e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161012a565b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff8116811461049257600080fd5b50565b600080604083850312156104a857600080fd5b82356104b381610470565b946020939093013593505050565b6000602082840312156104d357600080fd5b81356104de81610470565b9392505050565b6000602082840312156104f757600080fd5b815180151581146104de57600080fdfea2646970667358221220d75d238657525e68e9d08d25dd50b1e59ddd7dacae9f874f06edab64b0261eae64736f6c634300081300332c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c72c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cd2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca3b60ce0b93c245c9380528a68af18188f1da33fcb86fc7f01e50bb31d116159a7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec382600a2b12f2bedfdadd0fde1768f2416392cb05081ac1ae7ca466d1150ee0862b86ff79e1b5adb224d25415c777ccd653d71e2187f2e9ec212c12480572d79ef700000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000004d8858c200000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000008ddf15124b249d30d7a25cd4fde47c4f642057a20000000000000000000000008ddf15124b249d30d7a25cd4fde47c4f642057a20000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d0000000000000000000000000000000000000000000000000000000000000004746869730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047468697300000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x60806040526004361061026e5760003560e01c80637594af7811610153578063b361bbbb116100cb578063d547741f1161007f578063dce6950611610064578063dce6950614610800578063dd62ed3e14610862578063ea8d1984146108cb57600080fd5b8063d547741f14610752578063d54a8d181461077257600080fd5b8063c7a6ec12116100b0578063c7a6ec12146106d2578063c8daadac146106f2578063ca15c8731461073257600080fd5b8063b361bbbb14610692578063c49b9a80146106b257600080fd5b806395d89b41116101225780639a7a23d6116101075780639a7a23d61461063d578063a217fddf1461065d578063a9059cbb1461067257600080fd5b806395d89b411461060857806395f31dde1461061d57600080fd5b80637594af78146105575780638a8c523c146105775780639010d07c1461058c57806391d14854146105c457600080fd5b80632f2ff15d116101e657806340667d46116101b55780635af0e8441161019a5780635af0e844146104c25780636f784216146104e257806370a082311461050257600080fd5b806340667d4614610482578063533ff7ec146104a257600080fd5b80632f2ff15d146103e1578063313ce56714610401578063316ef97e1461044257806336568abe1461046257600080fd5b80631d2a77201161023d578063248a9ca311610222578063248a9ca314610371578063296f0a0c146103a15780632ae711ed146103c157600080fd5b80631d2a77201461032f57806323b872dd1461035157600080fd5b806301ffc9a71461027a57806306fdde03146102af578063095ea7b3146102d157806318160ddd146102f157600080fd5b3661027557005b600080fd5b34801561028657600080fd5b5061029a610295366004613893565b6108eb565b60405190151581526020015b60405180910390f35b3480156102bb57600080fd5b506102c4610947565b6040516102a691906138f9565b3480156102dd57600080fd5b5061029a6102ec366004613966565b6109f8565b3480156102fd57600080fd5b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca545b6040519081526020016102a6565b34801561033b57600080fd5b5061034f61034a3660046139bf565b610a0e565b005b34801561035d57600080fd5b5061029a61036c366004613aae565b610a2b565b34801561037d57600080fd5b5061032161038c366004613aea565b60009081526020819052604090206001015490565b3480156103ad57600080fd5b5061034f6103bc366004613b03565b610aa9565b3480156103cd57600080fd5b5061034f6103dc366004613b03565b610b0f565b3480156103ed57600080fd5b5061034f6103fc366004613b1e565b610cf8565b34801561040d57600080fd5b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c95460405160ff90911681526020016102a6565b34801561044e57600080fd5b5061034f61045d366004613b4a565b610d1a565b34801561046e57600080fd5b5061034f61047d366004613b1e565b610e30565b34801561048e57600080fd5b5061034f61049d366004613b84565b610e52565b3480156104ae57600080fd5b5061034f6104bd366004613b03565b610ee9565b3480156104ce57600080fd5b5061034f6104dd366004613aea565b610f4f565b3480156104ee57600080fd5b5061034f6104fd366004613aea565b610fc6565b34801561050e57600080fd5b5061032161051d366004613b03565b6001600160a01b031660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602052604090205490565b34801561056357600080fd5b5061034f610572366004613b84565b61102a565b34801561058357600080fd5b5061034f611069565b34801561059857600080fd5b506105ac6105a7366004613ba1565b6110c3565b6040516001600160a01b0390911681526020016102a6565b3480156105d057600080fd5b5061029a6105df366004613b1e565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561061457600080fd5b506102c46110db565b34801561062957600080fd5b5061034f610638366004613aea565b61110c565b34801561064957600080fd5b5061034f610658366004613bc3565b61117d565b34801561066957600080fd5b50610321600081565b34801561067e57600080fd5b5061029a61068d366004613966565b611193565b34801561069e57600080fd5b5061034f6106ad366004613bfa565b6111a0565b3480156106be57600080fd5b5061034f6106cd366004613b84565b61131f565b3480156106de57600080fd5b5061034f6106ed3660046139bf565b61132b565b3480156106fe57600080fd5b5061071261070d366004613bfa565b611343565b6040805194855260208501939093529183015260608201526080016102a6565b34801561073e57600080fd5b5061032161074d366004613aea565b6115df565b34801561075e57600080fd5b5061034f61076d366004613b1e565b6115f6565b34801561077e57600080fd5b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ce547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d0547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cf54604080519384526020840192909252908201526060016102a6565b34801561080c57600080fd5b5061029a61081b366004613b1e565b6001600160a01b031660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960209081526040808320938352929052205460ff1690565b34801561086e57600080fd5b5061032161087d366004613bfa565b6001600160a01b0391821660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602090815260408083209390941682526001909201909152205490565b3480156108d757600080fd5b5061034f6108e6366004613b84565b611600565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806109415750610941826116bc565b92915050565b60607f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7805461097590613c24565b80601f01602080910402602001604051908101604052809291908181526020018280546109a190613c24565b80156109ee5780601f106109c3576101008083540402835291602001916109ee565b820191906000526020600020905b8154815290600101906020018083116109d157829003601f168201915b5050505050905090565b6000610a05338484611753565b50600192915050565b6000610a1a81336118a8565b610a2683836000611948565b505050565b60007f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7610a598585856119e9565b6001600160a01b0385166000908152600482016020908152604080832033808552600190910190925290912054610a9c918791610a97908790613ca6565b611753565b60019150505b9392505050565b6000610ab581336118a8565b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6002805403610b655760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600280556000610b7581336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c76001600160a01b038316610bec5760405162461bcd60e51b815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152606401610b5c565b600081600f01541180610c03575060008160100154115b610c4f5760405162461bcd60e51b815260206004820152600c60248201527f5a45524f5f42414c414e434500000000000000000000000000000000000000006044820152606401610b5c565b600f81018054601083018054600093849055929055908115610ccd576000856001600160a01b03168360405160006040518083038185875af1925050503d8060008114610cb8576040519150601f19603f3d011682016040523d82523d6000602084013e610cbd565b606091505b5050905080610ccb57600080fd5b505b8015610cec57600e830154610cec906001600160a01b03168683611d33565b50506001600255505050565b610d028282611dfa565b6000828152600160205260409020610a269082611e20565b6000610d2681336118a8565b7f86ff79e1b5adb224d25415c777ccd653d71e2187f2e9ec212c12480572d79ef78403610d6b57610bb8831115610d5c57600080fd5b610bb8821115610d6b57600080fd5b7f600a2b12f2bedfdadd0fde1768f2416392cb05081ac1ae7ca466d1150ee0862b8403610db057610bb8831115610da157600080fd5b610bb8821115610db057600080fd5b60008481527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cd60205260409020600281018490556001018290557f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7610e158385613cb9565b60009586526006909101602052604090942093909355505050565b610e3a8282611e35565b6000828152600160205260409020610a269082611ebd565b6000610e5e81336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101008415159081029190911790915560408051918252517f6bcabd360224c151477bb16b5a2ad6271f8c1f1345575b8d4490e046b9b96fc39181900360200190a15050565b6000610ef581336118a8565b507f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000610f5b81336118a8565b6032821015610f6957600080fd5b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec382610fbc83610fb67f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca5490565b90611ed2565b6001909101555050565b6000610fd281336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7906110209084611ed2565b6012909101555050565b600061103681336118a8565b507f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec385805460ff1916911515919091179055565b600061107581336118a8565b507f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b6000828152600160205260408120610aa29083611f63565b60607f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7600101805461097590613c24565b600061111881336118a8565b603282101561112657600080fd5b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38261117383610fb67f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ca5490565b6002909101555050565b600061118981336118a8565b610a268383611f6f565b6000610a053384846119e9565b60006111ac81336118a8565b306001600160a01b038316036112045760405162461bcd60e51b815260206004820152601060248201527f52454445454d5f4f574e5f544f4b454e000000000000000000000000000000006044820152606401610b5c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282906001600160a01b0382169063a9059cbb90869083906370a0823190602401602060405180830381865afa15801561126d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112919190613ccc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156112f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113189190613ce5565b5050505050565b61132881610e52565b50565b600061133781336118a8565b610a2683836001611948565b7f54a61fc1270c90ad1c522bb0b76231a89910caa36c59e8fe68fafadaec70220c600080807f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c77f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3826114167f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d896001600160a01b031660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960209081526040808320938352929052205460ff1690565b15801561148657506001600160a01b03871660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d845290915290205460ff16155b156115ae576001600160a01b038816600090815260058301602052604090205460ff16156114d6577f86ff79e1b5adb224d25415c777ccd653d71e2187f2e9ec212c12480572d79ef795506115ae565b6001600160a01b038716600090815260058301602052604090205460ff161561158a576004810154600582015461150d9043613ca6565b101561156257507fea54d35234a268da5de307f513b1064e5a4d637cfef76180b0dbb003c2c6ff89600081815260069092016020526040909120805460028201546001909201549296509450925090506115d6565b7f600a2b12f2bedfdadd0fde1768f2416392cb05081ac1ae7ca466d1150ee0862b95506115ae565b7f5276e5bdffc77c7451e31f8f5537312e9d19da001480f9e0395a06c9c870b47e95505b5060008581526006909101602052604090208054600282015460019092015490945090925090505b92959194509250565b600081815260016020526040812061094190612053565b610e3a828261205d565b600061160c81336118a8565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d880547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100841515908102919091179091556040519081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7907f90b6a5dc00b3a619a544f08e22e2fd82d67cccf7ef76f473018e53551a6a1e8e906020015b60405180910390a1505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061094157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610941565b6001600160a01b0383166117a95760405162461bcd60e51b815260206004820152601160248201527f46524f4d5f5a45524f5f414444524553530000000000000000000000000000006044820152606401610b5c565b6001600160a01b0382166117ff5760405162461bcd60e51b815260206004820152600f60248201527f544f5f5a45524f5f4144445245535300000000000000000000000000000000006044820152606401610b5c565b6001600160a01b0383811660008181527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602090815260408083209487168084526001909501825291829020859055815185815291517f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c79493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92592908290030190a350505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611944576118e4816001600160a01b03166014612083565b6118ef836020612083565b604051602001611900929190613d02565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905262461bcd60e51b8252610b5c916004016138f9565b5050565b60005b82518110156119e3576001600160a01b03841660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a796020526040812084518492908690859081106119a2576119a2613d83565b6020026020010151815260200190815260200160002060006101000a81548160ff0219169083151502179055506001816119dc9190613cb9565b905061194b565b50505050565b6001600160a01b038316611a3f5760405162461bcd60e51b815260206004820152601160248201527f46524f4d5f5a45524f5f414444524553530000000000000000000000000000006044820152606401610b5c565b6001600160a01b038216611a955760405162461bcd60e51b815260206004820152600f60248201527f544f5f5a45524f5f4144445245535300000000000000000000000000000000006044820152606401610b5c565b60008111611ae55760405162461bcd60e51b815260206004820152600b60248201527f5a45524f5f414d4f554e540000000000000000000000000000000000000000006044820152606401610b5c565b611aee836122ac565b611af98383836125bb565b6000806000611b088686611343565b935093509350506000611b387f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c790565b30600090815260048201602052604081209192506007830191908615611c5c578515611bad576000611b6a8988611ed2565b905080846001016000828254611b809190613cb9565b9091555050835481908590600090611b99908490613cb9565b90915550611ba990508183613cb9565b9150505b8415611c02576000611bbf8987611ed2565b905080846002016000828254611bd59190613cb9565b9091555050835481908590600090611bee908490613cb9565b90915550611bfe90508183613cb9565b9150505b80826000016000828254611c169190613cb9565b909155505060405181815230906001600160a01b038c16907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b6000611c68828a613ca6565b6001600160a01b038c166000908152600487016020526040812080549293508b92909190611c97908490613ca6565b90915550506001600160a01b038a16600090815260048601602052604081208054839290611cc6908490613cb9565b92505081905550896001600160a01b03168b6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611d1291815260200190565b60405180910390a3611d268b8b8b8461273f565b5050505050505050505050565b6040516001600160a01b038316602482015260448101829052610a269084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612744565b600082815260208190526040902060010154611e1681336118a8565b610a268383612829565b6000610aa2836001600160a01b0384166128c7565b6001600160a01b0381163314611eb35760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610b5c565b6119448282612916565b6000610aa2836001600160a01b038416612995565b6000620186a0821115611f275760405162461bcd60e51b815260206004820152601260248201527f494e56414c49445f50455243454e5441474500000000000000000000000000006044820152606401610b5c565b611f3c670de0b6b3a7640000620186a0613db2565b670de0b6b3a7640000611f4f8486613db2565b611f599190613db2565b610aa29190613dc9565b6000610aa28383612a82565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c781611ff557600d8101546001600160a01b0390811690841603611ff55760405162461bcd60e51b815260206004820152600c60248201527f554e49535741505f5041495200000000000000000000000000000000000000006044820152606401610b5c565b6001600160a01b0383166000818152600583016020908152604091829020805460ff19168615159081179091558251938452908301527fffa9187bf1f18bf477bd0ea1bcbb64e93b6a98132473929edfce215cd9b16fab91016116af565b6000610941825490565b60008281526020819052604090206001015461207981336118a8565b610a268383612916565b60606000612092836002613db2565b61209d906002613cb9565b67ffffffffffffffff8111156120b5576120b5613990565b6040519080825280601f01601f1916602001820160405280156120df576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061211657612116613d83565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061217957612179613d83565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006121b5846002613db2565b6121c0906001613cb9565b90505b600181111561225d577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061220157612201613d83565b1a60f81b82828151811061221757612217613d83565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361225681613e04565b90506121c3565b508315610aa25760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b5c565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156ce547f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec384547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7917f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3829160009161234091612b23565b90508260120154811015801561235b5750601183015460ff16155b80156123775750600d8301546001600160a01b03858116911614155b801561238c57506011830154610100900460ff165b80156123d057506001600160a01b03841660009081527ff5df84ad4d78830ee1c523fb749c590ca6c847f665d9a7a6e01ebd5b61f6fc82602052604090205460ff16155b156119e35760118301805460ff191660011790556040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526007840154600885015461242991612b39565b6020820181905261243b908390612b5e565b60408201819052600885018054600090612456908490613ca6565b90915550506007840154600985015461246e91612b39565b60608201819052612480908390612b5e565b6080820181905261249390600290613dc9565b60a082018190526080820180516124ab908390613ca6565b905250608081015160a08201516124c29190613cb9565b6009850180546000906124d6908490613ca6565b9091555050608081015160408201516000916124f191613cb9565b9050816040015182608001518360a0015161250c9190613cb9565b6125169190613cb9565b60078601805460009061252a908490613ca6565b909155505080156125a357600e8501546000906125529030906001600160a01b031684612b73565b90506125828360a00151612573856020015184612b5e90919063ffffffff16565b61257d9084613ca6565b612f7c565b6125a161259c846020015183612b5e90919063ffffffff16565b61317e565b505b505047600f8401555050601101805460ff1916905550565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3826126487f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d856001600160a01b031660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a7960209081526040808320938352929052205460ff1690565b1580156126b857506001600160a01b03831660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f8137d429fdc167deec0182bbcd112bc5d292aab36755d624a12438052028a24d845290915290205460ff16155b15612713578054610100900460ff166127135760405162461bcd60e51b815260206004820152601060248201527f54524144494e475f44495341424c4544000000000000000000000000000000006044820152606401610b5c565b61271d8383613206565b612728848484613341565b600381015460ff16156119e3576119e3848461354c565b6119e3565b6000612799826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135869092919063ffffffff16565b805190915015610a2657808060200190518101906127b79190613ce5565b610a265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b5c565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611944576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556128833390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600081815260018301602052604081205461290e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610941565b506000610941565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1615611944576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008181526001830160205260408120548015612a785760006129b9600183613ca6565b85549091506000906129cd90600190613ca6565b905060008660000182815481106129e6576129e6613d83565b9060005260206000200154905080876000018481548110612a0957612a09613d83565b600091825260208083209091019290925582815260018901909152604090208490558654879080612a3c57612a3c613e39565b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050610941565b6000915050610941565b81546000908210612afb5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e60448201527f64730000000000000000000000000000000000000000000000000000000000006064820152608401610b5c565b826000018281548110612b1057612b10613d83565b9060005260206000200154905092915050565b6000818310612b325781610aa2565b5090919050565b600081600003612b4b57506000610941565b81611f59670de0b6b3a764000085613db2565b6000670de0b6b3a7640000611f598385613db2565b6040805160028082526060820183526000927f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c792849290916020830190803683370190505090508581600081518110612bce57612bce613d83565b60200260200101906001600160a01b031690816001600160a01b0316815250508481600181518110612c0257612c02613d83565b6001600160a01b039283166020918202929092010152600c8301546040517f095ea7b30000000000000000000000000000000000000000000000000000000081529082166004820152602481018690529087169063095ea7b3906044016020604051808303816000875af1158015612c7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca29190613ce5565b506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015285906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612d05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d299190613ccc565b600c85015460138601546040517f5c11d7950000000000000000000000000000000000000000000000000000000081529293506001600160a01b0391821692635c11d79592612d85928b926000928a9216904290600401613e68565b600060405180830381600087803b158015612d9f57600080fd5b505af1158015612db3573d6000803e3d6000fd5b5050505060138401546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526000918416906370a0823190602401602060405180830381865afa158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e429190613ccc565b60138601546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820184905292935091169063095ea7b390604401600060405180830381600087803b158015612ead57600080fd5b505af1158015612ec1573d6000803e3d6000fd5b5050506013860154612ee291506001600160a01b038581169116308461359d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282906001600160a01b038516906370a0823190602401602060405180830381865afa158015612f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f659190613ccc565b612f6f9190613ca6565b9998505050505050505050565b811580612f87575080155b15612f90575050565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d3547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c790612fe99030906001600160a01b031685611753565b600e810154600c8201546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526024810185905291169063095ea7b3906044016020604051808303816000875af115801561305b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061307f9190613ce5565b50600c810154600e820154600b8301546040517fe8e337000000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039283166024820152604481018790526064810186905260006084820181905260a482015290821660c48201524260e482015291169063e8e3370090610104016060604051808303816000875af1158015613121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131459190613ed9565b505060408051858152602081018590527fcb1652de9aeec38545fc281847b3dbfc89aab56dfa907b1ab68466f602c36fb49250016116af565b806000036131895750565b7f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d1547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156d5547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c791611944916001600160a01b03908116911684611d33565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38280546301000000900460ff1615610a265780600101548261327c856001600160a01b031660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cb602052604090205490565b6132869190613cb9565b1115806132f557506001600160a01b03831660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f3b60ce0b93c245c9380528a68af18188f1da33fcb86fc7f01e50bb31d116159a845290915290205460ff165b610a265760405162461bcd60e51b815260206004820152601360248201527f4d41585f57414c4c45545f4558434545444544000000000000000000000000006044820152606401610b5c565b6001600160a01b03831660009081527f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156cc60205260409020547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7907f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec3829060ff161561348b5780600201548311158061343a57506001600160a01b03841660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f9371c8791e1754c08ca054e61e0f5b5d74d999eee60ddd36b3906606c1f7edc9845290915290205460ff165b6134865760405162461bcd60e51b815260206004820152601160248201527f54585f4c494d49545f45584345454445440000000000000000000000000000006044820152606401610b5c565b611318565b80600201548311158061350057506001600160a01b03851660009081527f1d95baea637a3cde7fdd0ae99f029fa778aa88cd7a3e559a822bc184c8996a79602090815260408083207f9371c8791e1754c08ca054e61e0f5b5d74d999eee60ddd36b3906606c1f7edc9845290915290205460ff165b6113185760405162461bcd60e51b815260206004820152601160248201527f54585f4c494d49545f45584345454445440000000000000000000000000000006044820152606401610b5c565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec382805462010000900460ff16610a2657610a2683836135ee565b6060613595848460008561371b565b949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526119e39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611d78565b7f7926f07972717fa978f81626d5b27d4e4d4766129ed4f446fbfa38a013fec38280547f2c4f694c637a83dbfc589ed9bac3b5d1433e16fb13a156deb23698d3504156c7919062010000900460ff161561368a5760405162461bcd60e51b815260206004820152601f60248201527f494e495449414c5f4c49515549444954595f414c52454144595f4144444544006044820152606401610b5c565b600d8201546001600160a01b0384811691161480156136e057506001600160a01b03841660009081527fb8a5653c31e8e07e8ef5c22c947cfb9ffb7305e1fa1930db175624824a230ddf602052604090205460ff165b156119e35780544360058301557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff1662010100179055505050565b6060824710156137935760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b5c565b843b6137e15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b5c565b600080866001600160a01b031685876040516137fd9190613f07565b60006040518083038185875af1925050503d806000811461383a576040519150601f19603f3d011682016040523d82523d6000602084013e61383f565b606091505b509150915061384f82828661385a565b979650505050505050565b60608315613869575081610aa2565b8251156138795782518084602001fd5b8160405162461bcd60e51b8152600401610b5c91906138f9565b6000602082840312156138a557600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610aa257600080fd5b60005b838110156138f05781810151838201526020016138d8565b50506000910152565b60208152600082518060208401526139188160408501602087016138d5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b80356001600160a01b038116811461396157600080fd5b919050565b6000806040838503121561397957600080fd5b6139828361394a565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156139d257600080fd5b6139db8361394a565b915060208084013567ffffffffffffffff808211156139f957600080fd5b818601915086601f830112613a0d57600080fd5b813581811115613a1f57613a1f613990565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715613a6257613a62613990565b604052918252848201925083810185019189831115613a8057600080fd5b938501935b82851015613a9e57843584529385019392850192613a85565b8096505050505050509250929050565b600080600060608486031215613ac357600080fd5b613acc8461394a565b9250613ada6020850161394a565b9150604084013590509250925092565b600060208284031215613afc57600080fd5b5035919050565b600060208284031215613b1557600080fd5b610aa28261394a565b60008060408385031215613b3157600080fd5b82359150613b416020840161394a565b90509250929050565b600080600060608486031215613b5f57600080fd5b505081359360208301359350604090920135919050565b801515811461132857600080fd5b600060208284031215613b9657600080fd5b8135610aa281613b76565b60008060408385031215613bb457600080fd5b50508035926020909101359150565b60008060408385031215613bd657600080fd5b613bdf8361394a565b91506020830135613bef81613b76565b809150509250929050565b60008060408385031215613c0d57600080fd5b613c168361394a565b9150613b416020840161394a565b600181811c90821680613c3857607f821691505b602082108103613c71577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561094157610941613c77565b8082018082111561094157610941613c77565b600060208284031215613cde57600080fd5b5051919050565b600060208284031215613cf757600080fd5b8151610aa281613b76565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613d3a8160178501602088016138d5565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351613d778160288401602088016138d5565b01602801949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808202811582820484141761094157610941613c77565b600082613dff577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600081613e1357613e13613c77565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015613eb85784516001600160a01b031683529383019391830191600101613e93565b50506001600160a01b03969096166060850152505050608001529392505050565b600080600060608486031215613eee57600080fd5b8351925060208401519150604084015190509250925092565b60008251613f198184602087016138d5565b919091019291505056fea26469706673582212202efdf04f4feef6e2a06a7dd48b09fe95b14d7a61eb189004f4fb1b09664e3c9464736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000004d8858c200000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000008ddf15124b249d30d7a25cd4fde47c4f642057a20000000000000000000000008ddf15124b249d30d7a25cd4fde47c4f642057a20000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d0000000000000000000000000000000000000000000000000000000000000004746869730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047468697300000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): this
Arg [1] : _symbol (string): this
Arg [2] : _supply (uint256): 333000000000
Arg [3] : _maxTxnPercentage (uint256): 900
Arg [4] : _maxBalancePercentage (uint256): 2000
Arg [5] : _liquidityThresholdPercentage (uint256): 200
Arg [6] : _buyFees (uint256[2]): 1000,2000
Arg [7] : _sellFees (uint256[2]): 1000,2000
Arg [8] : _addresses (address[3]): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,0x8DdF15124b249d30D7a25cd4fDe47C4F642057A2,0x8DdF15124b249d30D7a25cd4fDe47C4F642057A2
Arg [9] : _v2Router (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D

-----Encoded View---------------
18 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [2] : 0000000000000000000000000000000000000000000000000000004d8858c200
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000384
Arg [4] : 00000000000000000000000000000000000000000000000000000000000007d0
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000c8
Arg [6] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [7] : 00000000000000000000000000000000000000000000000000000000000007d0
Arg [8] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [9] : 00000000000000000000000000000000000000000000000000000000000007d0
Arg [10] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [11] : 0000000000000000000000008ddf15124b249d30d7a25cd4fde47c4f642057a2
Arg [12] : 0000000000000000000000008ddf15124b249d30d7a25cd4fde47c4f642057a2
Arg [13] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [15] : 7468697300000000000000000000000000000000000000000000000000000000
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [17] : 7468697300000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

76395:8408:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55429:227;;;;;;;;;;-1:-1:-1;55429:227:0;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;55429:227:0;;;;;;;;61777:114;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;64390:148::-;;;;;;;;;;-1:-1:-1;64390:148:0;;;;;:::i;:::-;;:::i;62141:122::-;;;;;;;;;;-1:-1:-1;62216:41:0;;62141:122;;;1864:25:1;;;1852:2;1837:18;62141:122:0;1718:177:1;58698:187:0;;;;;;;;;;-1:-1:-1;58698:187:0;;;;;:::i;:::-;;:::i;:::-;;64704:357;;;;;;;;;;-1:-1:-1;64704:357:0;;;;;:::i;:::-;;:::i;51474:123::-;;;;;;;;;;-1:-1:-1;51474:123:0;;;;;:::i;:::-;51540:7;51567:12;;;;;;;;;;:22;;;;51474:123;79747:235;;;;;;;;;;-1:-1:-1;79747:235:0;;;;;:::i;:::-;;:::i;79988:845::-;;;;;;;;;;-1:-1:-1;79988:845:0;;;;;:::i;:::-;;:::i;56800:165::-;;;;;;;;;;-1:-1:-1;56800:165:0;;;;;:::i;:::-;;:::i;62021:114::-;;;;;;;;;;-1:-1:-1;62091:38:0;;62021:114;;62091:38;;;;4634:36:1;;4622:2;4607:18;62021:114:0;4492:184:1;65067:643:0;;;;;;;;;;-1:-1:-1;65067:643:0;;;;;:::i;:::-;;:::i;57323:174::-;;;;;;;;;;-1:-1:-1;57323:174:0;;;;;:::i;:::-;;:::i;79061:235::-;;;;;;;;;;-1:-1:-1;79061:235:0;;;;;:::i;:::-;;:::i;79504:237::-;;;;;;;;;;-1:-1:-1;79504:237:0;;;;;:::i;:::-;;:::i;78588:354::-;;;;;;;;;;-1:-1:-1;78588:354:0;;;;;:::i;:::-;;:::i;66008:315::-;;;;;;;;;;-1:-1:-1;66008:315:0;;;;;:::i;:::-;;:::i;62269:146::-;;;;;;;;;;-1:-1:-1;62269:146:0;;;;;:::i;:::-;-1:-1:-1;;;;;62357:44:0;62334:7;62357:44;;;:35;:44;;;;;:52;;62269:146;77843:199;;;;;;;;;;-1:-1:-1;77843:199:0;;;;;:::i;:::-;;:::i;78048:154::-;;;;;;;;;;;;;:::i;56255:145::-;;;;;;;;;;-1:-1:-1;56255:145:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;5973:55:1;;;5955:74;;5943:2;5928:18;56255:145:0;5809:226:1;50472:139:0;;;;;;;;;;-1:-1:-1;50472:139:0;;;;;:::i;:::-;50550:4;50574:12;;;;;;;;;;;-1:-1:-1;;;;;50574:29:0;;;;;;;;;;;;;;;50472:139;61897:118;;;;;;;;;;;;;:::i;78208:374::-;;;;;;;;;;-1:-1:-1;78208:374:0;;;;;:::i;:::-;;:::i;79302:196::-;;;;;;;;;;-1:-1:-1;79302:196:0;;;;;:::i;:::-;;:::i;48437:49::-;;;;;;;;;;-1:-1:-1;48437:49:0;48482:4;48437:49;;64544:154;;;;;;;;;;-1:-1:-1;64544:154:0;;;;;:::i;:::-;;:::i;80915:297::-;;;;;;;;;;-1:-1:-1;80915:297:0;;;;;:::i;:::-;;:::i;78948:107::-;;;;;;;;;;-1:-1:-1;78948:107:0;;;;;:::i;:::-;;:::i;58891:186::-;;;;;;;;;;-1:-1:-1;58891:186:0;;;;;:::i;:::-;;:::i;62598:1319::-;;;;;;;;;;-1:-1:-1;62598:1319:0;;;;;:::i;:::-;;:::i;:::-;;;;6856:25:1;;;6912:2;6897:18;;6890:34;;;;6940:18;;;6933:34;6998:2;6983:18;;6976:34;6843:3;6828:19;62598:1319:0;6625:391:1;56574:134:0;;;;;;;;;;-1:-1:-1;56574:134:0;;;;;:::i;:::-;;:::i;57058:170::-;;;;;;;;;;-1:-1:-1;57058:170:0;;;;;:::i;:::-;;:::i;63923:417::-;;;;;;;;;;-1:-1:-1;64192:19:0;64236:22;64267:26;;64302:25;;63923:417;;;7223:25:1;;;7279:2;7264:18;;7257:34;;;;7307:18;;;7300:34;7211:2;7196:18;63923:417:0;7021:319:1;58449:199:0;;;;;;;;;;-1:-1:-1;58449:199:0;;;;;:::i;:::-;-1:-1:-1;;;;;58579:54:0;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;:63;;;;;;;;;;;58449:199;62421:171;;;;;;;;;;-1:-1:-1;62421:171:0;;;;;:::i;:::-;-1:-1:-1;;;;;62524:42:0;;;62501:7;62524:42;;;:35;:42;;;;;;;;:62;;;;;;:53;;;;:62;;;;;;62421:171;65716:286;;;;;;;;;;-1:-1:-1;65716:286:0;;;;;:::i;:::-;;:::i;55429:227::-;55514:4;55538:57;;;55553:42;55538:57;;:110;;;55612:36;55636:11;55612:23;:36::i;:::-;55531:117;55429:227;-1:-1:-1;;55429:227:0:o;61777:114::-;61822:13;19886:31;61844:41;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61777:114;:::o;64390:148::-;64464:4;64477:37;64486:10;64498:7;64507:6;64477:8;:37::i;:::-;-1:-1:-1;64528:4:0;64390:148;;;;:::o;58698:187::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;58838:41:::1;58857:7;58866:5;58873;58838:18;:41::i;:::-;58698:187:::0;;;:::o;64704:357::-;64816:4;19886:31;64911:36;64921:6;64929:9;64940:6;64911:9;:36::i;:::-;-1:-1:-1;;;;;64983:19:0;;;;;;:11;;;:19;;;;;;;;64971:10;64983:42;;;:30;;;;:42;;;;;;;64954:81;;64963:6;;64983:51;;65028:6;;64983:51;:::i;:::-;64954:8;:81::i;:::-;65051:4;65044:11;;;64704:357;;;;;;:::o;79747:235::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;-1:-1:-1;79943:21:0;:33;;;::::1;-1:-1:-1::0;;;;;79943:33:0;;;::::1;::::0;;;::::1;::::0;;79747:235::o;79988:845::-;75386:1;75983:7;;:19;75975:63;;;;-1:-1:-1;;;75975:63:0;;8311:2:1;75975:63:0;;;8293:21:1;8350:2;8330:18;;;8323:30;8389:33;8369:18;;;8362:61;8440:18;;75975:63:0;;;;;;;;;75386:1;76116:18;;48482:4:::1;50041:30;48482:4:::0;42796:10;50041;:30::i;:::-:1;19886:31:::0;-1:-1:-1;;;;;80209:23:0;::::2;80201:48;;;::::0;-1:-1:-1;;;80201:48:0;;8671:2:1;80201:48:0::2;::::0;::::2;8653:21:1::0;8710:2;8690:18;;;8683:30;8749:14;8729:18;;;8722:42;8781:18;;80201:48:0::2;8469:336:1::0;80201:48:0::2;80294:1;80264:5;:27;;;:31;:71;;;;80334:1;80299:5;:32;;;:36;80264:71;80256:96;;;::::0;-1:-1:-1;;;80256:96:0;;9012:2:1;80256:96:0::2;::::0;::::2;8994:21:1::0;9051:2;9031:18;;;9024:30;9090:14;9070:18;;;9063:42;9122:18;;80256:96:0::2;8810:336:1::0;80256:96:0::2;80383:27;::::0;::::2;::::0;;80444:32:::2;::::0;::::2;::::0;;80361:19:::2;80485:31:::0;;;;80523:36;;;80383:27;80571:15;;80568:154:::2;;80598:12;80623:9;-1:-1:-1::0;;;;;80615:23:0::2;80646:11;80615:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80597:65;;;80677:7;80673:42;;80697:8;::::0;::::2;80673:42;80588:134;80568:154;80733:20:::0;;80730:98:::2;;80764:14;::::0;::::2;::::0;:56:::2;::::0;-1:-1:-1;;;;;80764:14:0::2;80792:9:::0;80803:16;80764:27:::2;:56::i;:::-;-1:-1:-1::0;;75342:1:0;76295:7;:22;-1:-1:-1;;;79988:845:0:o;56800:165::-;56885:30;56901:4;56907:7;56885:15;:30::i;:::-;56926:18;;;;:12;:18;;;;;:31;;56949:7;56926:22;:31::i;65067:643::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;60130:19:::1;65239:6;:16:::0;65236:104:::1;;65290:4;65274:12;:20;;65266:29;;;::::0;::::1;;65327:4;65312:11;:19;;65304:28;;;::::0;::::1;;60190:20;65351:6;:17:::0;65348:105:::1;;65403:4;65387:12;:20;;65379:29;;;::::0;::::1;;65440:4;65425:11;:19;;65417:28;;;::::0;::::1;;65461:38;65540:18:::0;;;:10;:18:::1;::::0;;;;:31:::1;::::0;::::1;:46:::0;;;65593:30:::1;;:44:::0;;;19886:31;65677:26:::1;65593:44:::0;65540:46;65677:26:::1;:::i;:::-;65646:18;::::0;;;:10:::1;::::0;;::::1;:18;::::0;;;;;:58;;;;-1:-1:-1;;;65067:643:0:o;57323:174::-;57411:33;57430:4;57436:7;57411:18;:33::i;:::-;57455:18;;;;:12;:18;;;;;:34;;57481:7;57455:25;:34::i;79061:235::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;79181:52;:62;;;::::1;;::::0;::::1;;::::0;;::::1;::::0;;;::::1;::::0;;;79255:35:::1;::::0;;491:41:1;;;79255:35:0;::::1;::::0;;;;479:2:1;79255:35:0;;::::1;79061:235:::0;;:::o;79504:237::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;-1:-1:-1;79703:20:0;:32;;;::::1;-1:-1:-1::0;;;;;79703:32:0;;;::::1;::::0;;;::::1;::::0;;79504:237::o;78588:354::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;78753:2:::1;78729:20;:26;;78721:35;;;::::0;::::1;;2230:30:::0;78892:44:::1;78915:20:::0;78892:13:::1;62216:41:::0;;;62141:122;78892:13:::1;:22:::0;::::1;:44::i;:::-;78863:26;::::0;;::::1;:73:::0;-1:-1:-1;;78588:354:0:o;66008:315::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;66260:17;;19886:31;;66260:57:::1;::::0;66287:29;66260:26:::1;:57::i;:::-;66230:27;::::0;;::::1;:87:::0;-1:-1:-1;;66008:315:0:o;77843:199::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;-1:-1:-1;77967:59:0;:69;;-1:-1:-1;;77967:69:0::1;::::0;::::1;;::::0;;;::::1;::::0;;77843:199::o;78048:154::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;-1:-1:-1;2230:30:0;78145:51;;;::::1;;;::::0;;78048:154::o;56255:145::-;56337:7;56364:18;;;:12;:18;;;;;:28;;56386:5;56364:21;:28::i;61897:118::-;61944:13;19886:31;61973:36;;61966:43;;;;;:::i;78208:374::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;78385:2:::1;78357:24;:30;;78349:39;;;::::0;::::1;;2230:30:::0;78528:48:::1;78551:24:::0;78528:13:::1;62216:41:::0;;;62141:122;78528:48:::1;78495:30;::::0;;::::1;:81:::0;-1:-1:-1;;78208:374:0:o;79302:196::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;79444:48:::1;79473:11;79486:5;79444:28;:48::i;64544:154::-:0;64621:4;64634:40;64644:10;64656:9;64667:6;64634:9;:40::i;80915:297::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;81077:4:::1;-1:-1:-1::0;;;;;81059:23:0;::::1;::::0;81051:52:::1;;;::::0;-1:-1:-1;;;81051:52:0;;9693:2:1;81051:52:0::1;::::0;::::1;9675:21:1::0;9732:2;9712:18;;;9705:30;9771:18;9751;;;9744:46;9807:18;;81051:52:0::1;9491:340:1::0;81051:52:0::1;81175:30;::::0;;;;81199:4:::1;81175:30;::::0;::::1;5955:74:1::0;81134:6:0;;-1:-1:-1;;;;;81148:14:0;::::1;::::0;::::1;::::0;81163:10;;81148:14;;81175:15:::1;::::0;5928:18:1;;81175:30:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81148:58;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;10217:55:1;;;81148:58:0::1;::::0;::::1;10199:74:1::0;10289:18;;;10282:34;10172:18;;81148:58:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;81044:168;80915:297:::0;;;:::o;78948:107::-;79013:36;79040:8;79013:26;:36::i;:::-;78948:107;:::o;58891:186::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;59031:40:::1;59050:7;59059:5;59066:4;59031:18;:40::i;62598:1319::-:0;60320:20;62718:15;;;19886:31;2230:30;63031:48;58181:24;63072:6;-1:-1:-1;;;;;58579:54:0;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;:63;;;;;;;;;;;58449:199;63031:48;63030:49;:114;;;;-1:-1:-1;;;;;;58579:54:0;;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;58181:24;58579:63;;;;;;;;;;63092:52;63030:114;63019:736;;;-1:-1:-1;;;;;63164:39:0;;;;;;:31;;;:39;;;;;;;;63161:587;;;60130:19;63216:16;;63161:587;;;-1:-1:-1;;;;;63251:42:0;;;;;;:31;;;:42;;;;;;;;63248:500;;;63366:27;;;;63325:37;;;;63310:52;;:12;:52;:::i;:::-;63309:84;63306:385;;;-1:-1:-1;60394:33:0;63497:19;;;;:10;;;;:19;;;;;;:28;;63540:32;;;;63587:31;;;;;60394:33;;-1:-1:-1;63497:28:0;-1:-1:-1;63540:32:0;-1:-1:-1;63587:31:0;-1:-1:-1;63453:178:0;;63306:385;60190:20;63662:17;;63248:500;;;60255:24;63717:21;;63248:500;-1:-1:-1;63795:19:0;;;;:10;;;;:19;;;;;:28;;63832:32;;;;63873:31;;;;;63795:28;;-1:-1:-1;63832:32:0;;-1:-1:-1;63873:31:0;-1:-1:-1;62598:1319:0;;;;;;;;:::o;56574:134::-;56646:7;56673:18;;;:12;:18;;;;;:27;;:25;:27::i;57058:170::-;57144:31;57161:4;57167:7;57144:16;:31::i;65716:286::-;48482:4;50041:30;48482:4;42796:10;50041;:30::i;:::-;65913:28;:39;;;::::1;;::::0;::::1;;::::0;;::::1;::::0;;;::::1;::::0;;;65964:32:::1;::::0;491:41:1;;;19886:31:0;;65964:32:::1;::::0;479:2:1;464:18;65964:32:0::1;;;;;;;;65827:175;65716:286:::0;;:::o;50163:217::-;50248:4;50272:47;;;50287:32;50272:47;;:100;;-1:-1:-1;39996:25:0;39981:40;;;;50336:36;39872:157;66713:371;-1:-1:-1;;;;;66802:19:0;;66794:49;;;;-1:-1:-1;;;66794:49:0;;10779:2:1;66794:49:0;;;10761:21:1;10818:2;10798:18;;;10791:30;10857:19;10837:18;;;10830:47;10894:18;;66794:49:0;10577:341:1;66794:49:0;-1:-1:-1;;;;;66858:21:0;;66850:49;;;;-1:-1:-1;;;66850:49:0;;11125:2:1;66850:49:0;;;11107:21:1;11164:2;11144:18;;;11137:30;11203:17;11183:18;;;11176:45;11238:18;;66850:49:0;10923:339:1;66850:49:0;-1:-1:-1;;;;;66985:18:0;;;66908:38;66985:18;;;:11;:18;;;;;;;;:38;;;;;;:29;;;;:38;;;;;;:47;;;67046:32;;1864:25:1;;;67046:32:0;;19886:31;;66985:38;:18;67046:32;;;;;;;;;66787:297;66713:371;;;:::o;50901:384::-;50550:4;50574:12;;;;;;;;;;;-1:-1:-1;;;;;50574:29:0;;;;;;;;;;;;50977:301;;51113:41;51141:7;-1:-1:-1;;;;;51113:41:0;51151:2;51113:19;:41::i;:::-;51211:38;51239:4;51246:2;51211:19;:38::i;:::-;51034:230;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1;;;51020:246:0;;;;;;;:::i;50977:301::-;50901:384;;:::o;59083:241::-;59186:9;59182:137;59205:5;:12;59201:1;:16;59182:137;;;-1:-1:-1;;;;;59236:54:0;;:45;:54;;;1760:34;59236:54;;;;;59291:8;;59303;;59236:45;59291:5;;59297:1;;59291:8;;;;;;:::i;:::-;;;;;;;59236:64;;;;;;;;;;;;:75;;;;;;;;;;;;;;;;;;59224:1;59219:6;;;;;:::i;:::-;;;59182:137;;;;59083:241;;;:::o;67090:1677::-;-1:-1:-1;;;;;67183:20:0;;67175:50;;;;-1:-1:-1;;;67175:50:0;;10779:2:1;67175:50:0;;;10761:21:1;10818:2;10798:18;;;10791:30;10857:19;10837:18;;;10830:47;10894:18;;67175:50:0;10577:341:1;67175:50:0;-1:-1:-1;;;;;67240:23:0;;67232:51;;;;-1:-1:-1;;;67232:51:0;;11125:2:1;67232:51:0;;;11107:21:1;11164:2;11144:18;;;11137:30;11203:17;11183:18;;;11176:45;11238:18;;67232:51:0;10923:339:1;67232:51:0;67307:1;67298:6;:10;67290:34;;;;-1:-1:-1;;;67290:34:0;;12475:2:1;67290:34:0;;;12457:21:1;12514:2;12494:18;;;12487:30;12553:13;12533:18;;;12526:41;12584:18;;67290:34:0;12273:335:1;67290:34:0;67333:20;67346:6;67333:12;:20::i;:::-;67360:47;67381:6;67389:9;67400:6;67360:20;:47::i;:::-;67426:16;67451:19;67479:20;67509:37;67528:6;67536:9;67509:18;:37::i;:::-;67416:130;;;;;;;67555:38;67596:29;19886:31;;21124:171;67596:29;67767:4;67632:42;67747:26;;;:11;;;:26;;;;;67555:70;;-1:-1:-1;67677:19:0;;;;67747:26;67818:12;;67815:671;;67844:15;;67841:262;;67872:26;67901:28;:6;67917:11;67901:15;:28::i;:::-;67872:57;;67971:18;67942:13;:25;;;:47;;;;;;;:::i;:::-;;;;-1:-1:-1;;68000:44:0;;68026:18;;68000:13;;:22;;:44;;68026:18;;68000:44;:::i;:::-;;;;-1:-1:-1;68055:38:0;;-1:-1:-1;68075:18:0;68055:38;;:::i;:::-;;;67861:242;67841:262;68116:16;;68113:253;;68145:23;68171:29;:6;68187:12;68171:15;:29::i;:::-;68145:55;;68243:15;68213:13;:26;;;:45;;;;;;;:::i;:::-;;;;-1:-1:-1;;68269:41:0;;68295:15;;68269:13;;:22;;:41;;68295:15;;68269:41;:::i;:::-;;;;-1:-1:-1;68321:35:0;;-1:-1:-1;68341:15:0;68321:35;;:::i;:::-;;;68134:232;68113:253;68399:16;68376:11;:19;;;:39;;;;;;;:::i;:::-;;;;-1:-1:-1;;68429:49:0;;1864:25:1;;;68454:4:0;;-1:-1:-1;;;;;68429:49:0;;;;;1852:2:1;1837:18;68429:49:0;;;;;;;67815:671;68494:19;68516:25;68525:16;68516:6;:25;:::i;:::-;-1:-1:-1;;;;;68550:19:0;;;;;;:11;;;:19;;;;;:37;;68494:47;;-1:-1:-1;68581:6:0;;68550:19;;;:37;;68581:6;;68550:37;:::i;:::-;;;;-1:-1:-1;;;;;;;68594:22:0;;;;;;:11;;;:22;;;;;:45;;68628:11;;68594:22;:45;;68628:11;;68594:45;:::i;:::-;;;;;;;;68670:9;-1:-1:-1;;;;;68653:40:0;68662:6;-1:-1:-1;;;;;68653:40:0;;68681:11;68653:40;;;;1864:25:1;;1852:2;1837:18;;1718:177;68653:40:0;;;;;;;;68702:59;68722:6;68730:9;68741:6;68749:11;68702:19;:59::i;:::-;67168:1599;;;;;;;;67090:1677;;;:::o;23581:177::-;23691:58;;-1:-1:-1;;;;;10217:55:1;;23691:58:0;;;10199:74:1;10289:18;;;10282:34;;;23664:86:0;;23684:5;;23714:23;;10172:18:1;;23691:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23664:19;:86::i;51859:147::-;51540:7;51567:12;;;;;;;;;;:22;;;50041:30;50052:4;42796:10;50041;:30::i;:::-;51973:25:::1;51984:4;51990:7;51973:10;:25::i;35179:152::-:0;35249:4;35273:50;35278:3;-1:-1:-1;;;;;35298:23:0;;35273:4;:50::i;52907:218::-;-1:-1:-1;;;;;53003:23:0;;42796:10;53003:23;52995:83;;;;-1:-1:-1;;;52995:83:0;;12815:2:1;52995:83:0;;;12797:21:1;12854:2;12834:18;;;12827:30;12893:34;12873:18;;;12866:62;12964:17;12944:18;;;12937:45;12999:19;;52995:83:0;12613:411:1;52995:83:0;53091:26;53103:4;53109:7;53091:11;:26::i;35507:158::-;35580:4;35604:53;35612:3;-1:-1:-1;;;;;35632:23:0;;35604:7;:53::i;28263:246::-;28333:7;28365;28357:4;:15;;28349:46;;;;-1:-1:-1;;;28349:46:0;;13231:2:1;28349:46:0;;;13213:21:1;13270:2;13250:18;;;13243:30;13309:20;13289:18;;;13282:48;13347:18;;28349:46:0;13029:342:1;28349:46:0;27925:25;27869:4;27944:6;27925:25;:::i;:::-;27869:4;28449:13;28458:4;28449:6;:13;:::i;:::-;:32;;;;:::i;:::-;28448:55;;;;:::i;36465:158::-;36539:7;36590:22;36594:3;36606:5;36590:3;:22::i;66329:378::-;19886:31;66499:5;66495:87;;66538:19;;;;-1:-1:-1;;;;;66538:19:0;;;66523:34;;;;66515:59;;;;-1:-1:-1;;;66515:59:0;;14030:2:1;66515:59:0;;;14012:21:1;14069:2;14049:18;;;14042:30;14108:14;14088:18;;;14081:42;14140:18;;66515:59:0;13828:336:1;66515:59:0;-1:-1:-1;;;;;66590:44:0;;;;;;:31;;;:44;;;;;;;;;:52;;-1:-1:-1;;66590:52:0;;;;;;;;;;66654:47;;14337:74:1;;;14427:18;;;14420:50;66654:47:0;;14310:18:1;66654:47:0;14169:307:1;36004:117:0;36067:7;36094:19;36102:3;32761:18;;32678:109;52251:149;51540:7;51567:12;;;;;;;;;;:22;;;50041:30;50052:4;42796:10;50041;:30::i;:::-;52366:26:::1;52378:4;52384:7;52366:11;:26::i;41640:447::-:0;41715:13;41741:19;41773:10;41777:6;41773:1;:10;:::i;:::-;:14;;41786:1;41773:14;:::i;:::-;41763:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;41763:25:0;;41741:47;;41799:15;:6;41806:1;41799:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;;41825;:6;41832:1;41825:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;-1:-1:-1;41856:9:0;41868:10;41872:6;41868:1;:10;:::i;:::-;:14;;41881:1;41868:14;:::i;:::-;41856:26;;41851:131;41888:1;41884;:5;41851:131;;;41923:8;41932:5;41940:3;41932:11;41923:21;;;;;;;:::i;:::-;;;;41911:6;41918:1;41911:9;;;;;;;;:::i;:::-;;;;:33;;;;;;;;;;-1:-1:-1;41969:1:0;41959:11;;;;;41891:3;;;:::i;:::-;;;41851:131;;;-1:-1:-1;42000:10:0;;41992:55;;;;-1:-1:-1;;;41992:55:0;;14884:2:1;41992:55:0;;;14866:21:1;;;14903:18;;;14896:30;14962:34;14942:18;;;14935:62;15014:18;;41992:55:0;14682:356:1;69870:2343:0;70122:19;:28;70159:30;;19886:31;;2230:30;;69923:38;;70105:91;;:8;:91::i;:::-;70083:113;;70232:5;:27;;;70217:11;:42;;70216:80;;;;-1:-1:-1;70274:22:0;;;;;;70273:23;70216:80;:122;;;;-1:-1:-1;70319:19:0;;;;-1:-1:-1;;;;;70309:29:0;;;70319:19;;70309:29;;70216:122;:163;;;;-1:-1:-1;70351:28:0;;;;;;;;;70216:163;:215;;;;-1:-1:-1;;;;;;50574:29:0;;50550:4;50574:29;;;:12;;:29;:12;:29;;;;;70392:39;70216:215;70205:2003;;;70448:22;;;:29;;-1:-1:-1;;70448:29:0;70473:4;70448:29;;;-1:-1:-1;;;;;;;;70448:22:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70644:19:0;;;:28;70568:55;;;;:105;;:75;:105::i;:::-;70544:21;;;:129;;;70716:55;;:11;;:32;:55::i;:::-;70686:27;;;:85;;;70784:31;;;:62;;:31;;:62;;70686:85;;70784:62;:::i;:::-;;;;-1:-1:-1;;70979:19:0;;;:28;70902:56;;;;:106;;:76;:106::i;:::-;70877:22;;;:131;;;71052:56;;:11;;:32;:56::i;:::-;71021:28;;;:87;;;71151:32;;71182:1;;71151:32;:::i;:::-;71121:27;;;:62;;;71194:28;;;:59;;;;71121:62;;71194:59;:::i;:::-;;;-1:-1:-1;71333:28:0;;;;71303:27;;;;:58;;71333:28;71303:58;:::i;:::-;71266:32;;;:96;;:32;;:96;;;;;:::i;:::-;;;;-1:-1:-1;;71444:28:0;;;;71405:27;;;;71382:20;;71405:67;;;:::i;:::-;71382:90;;71594:8;:27;;;71554:8;:28;;;71515:8;:27;;;:67;;;;:::i;:::-;:106;;;;:::i;:::-;71483:19;;;:138;;:28;;:138;;;;;:::i;:::-;;;;-1:-1:-1;;71635:16:0;;71632:427;;71760:14;;;;71664:21;;71688:123;;71734:4;;-1:-1:-1;;;;;71760:14:0;71788:12;71688:25;:123::i;:::-;71664:147;;71824:142;71854:8;:27;;;71910:45;71933:8;:21;;;71910:13;:22;;:45;;;;:::i;:::-;71894:61;;:13;:61;:::i;:::-;71824:17;:142::i;:::-;71979:70;72003:45;72026:8;:21;;;72003:13;:22;;:45;;;;:::i;:::-;71979:23;:70::i;:::-;71653:406;71632:427;-1:-1:-1;;72140:21:0;72110:27;;;:51;-1:-1:-1;;72170:22:0;;:30;;-1:-1:-1;;72170:30:0;;;-1:-1:-1;69870:2343:0:o;83850:661::-;2230:30;84142:35;58181:24;84170:6;-1:-1:-1;;;;;58579:54:0;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;:63;;;;;;;;;;;58449:199;84142:35;84141:36;:79;;;;-1:-1:-1;;;;;;58579:54:0;;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;58181:24;58579:63;;;;;;;;;;84181:39;84141:79;84138:154;;;84239:24;;;;;;;84231:53;;;;-1:-1:-1;;;84231:53:0;;15245:2:1;84231:53:0;;;15227:21:1;15284:2;15264:18;;;15257:30;15323:18;15303;;;15296:46;15359:18;;84231:53:0;15043:340:1;84231:53:0;84300:37;84319:9;84330:6;84300:18;:37::i;:::-;84344:50;84368:6;84376:9;84387:6;84344:23;:50::i;:::-;84406:39;;;;;;84403:103;;;84456:42;84480:6;84488:9;84456:23;:42::i;84517:248::-;84687:72;59083:241;26015:761;26439:23;26465:69;26493:4;26465:69;;;;;;;;;;;;;;;;;26473:5;-1:-1:-1;;;;;26465:27:0;;;:69;;;;;:::i;:::-;26549:17;;26439:95;;-1:-1:-1;26549:21:0;26545:224;;26691:10;26680:30;;;;;;;;;;;;:::i;:::-;26672:85;;;;-1:-1:-1;;;26672:85:0;;15590:2:1;26672:85:0;;;15572:21:1;15629:2;15609:18;;;15602:30;15668:34;15648:18;;;15641:62;15739:12;15719:18;;;15712:40;15769:19;;26672:85:0;15388:406:1;54155:229:0;50550:4;50574:12;;;;;;;;;;;-1:-1:-1;;;;;50574:29:0;;;;;;;;;;;;54225:152;;54269:6;:12;;;;;;;;;;;-1:-1:-1;;;;;54269:29:0;;;;;;;;;:36;;-1:-1:-1;;54269:36:0;54301:4;54269:36;;;54352:12;42796:10;;42716:98;54352:12;-1:-1:-1;;;;;54325:40:0;54343:7;-1:-1:-1;;;;;54325:40:0;54337:4;54325:40;;;;;;;;;;54155:229;;:::o;30234:414::-;30297:4;32560:19;;;:12;;;:19;;;;;;30314:327;;-1:-1:-1;30357:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;30540:18;;30518:19;;;:12;;;:19;;;;;;:40;;;;30573:11;;30314:327;-1:-1:-1;30624:5:0;30617:12;;54392:230;50550:4;50574:12;;;;;;;;;;;-1:-1:-1;;;;;50574:29:0;;;;;;;;;;;;54463:152;;;54538:5;54506:12;;;;;;;;;;;-1:-1:-1;;;;;54506:29:0;;;;;;;;;;:37;;-1:-1:-1;;54506:37:0;;;54563:40;42796:10;;54506:12;;54563:40;;54538:5;54563:40;54392:230;;:::o;30824:1553::-;30890:4;31029:19;;;:12;;;:19;;;;;;31065:15;;31061:1309;;31427:21;31451:14;31464:1;31451:10;:14;:::i;:::-;31500:18;;31427:38;;-1:-1:-1;31480:17:0;;31500:22;;31521:1;;31500:22;:::i;:::-;31480:42;;31767:17;31787:3;:11;;31799:9;31787:22;;;;;;;;:::i;:::-;;;;;;;;;31767:42;;31933:9;31904:3;:11;;31916:13;31904:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;32010:23;;;:12;;;:23;;;;;;:36;;;32171:17;;32010:3;;32171:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;32266:3;:12;;:19;32279:5;32266:19;;;;;;;;;;;32259:26;;;32309:4;32302:11;;;;;;;;31061:1309;32353:5;32346:12;;;;;33131:204;33226:18;;33198:7;;33226:26;-1:-1:-1;33218:73:0;;;;-1:-1:-1;;;33218:73:0;;16190:2:1;33218:73:0;;;16172:21:1;16229:2;16209:18;;;16202:30;16268:34;16248:18;;;16241:62;16339:4;16319:18;;;16312:32;16361:19;;33218:73:0;15988:398:1;33218:73:0;33309:3;:11;;33321:5;33309:18;;;;;;;;:::i;:::-;;;;;;;;;33302:25;;33131:204;;;;:::o;27213:106::-;27271:7;27302:1;27298;:5;:13;;27310:1;27298:13;;;-1:-1:-1;27306:1:0;;27213:106;-1:-1:-1;27213:106:0:o;27958:160::-;28019:7;28038:1;28043;28038:6;28035:36;;-1:-1:-1;28062:1:0;28055:8;;28035:36;28111:1;28087:20;27869:4;28087:1;:20;:::i;28124:133::-;28194:7;27869:4;28218:13;28227:4;28218:6;:13;:::i;72219:1133::-;72488:16;;;72502:1;72488:16;;;;;;;;72369:7;;19886:31;;72369:7;;72488:16;;;;;;;;;;;;-1:-1:-1;72488:16:0;72464:40;;72521:17;72511:4;72516:1;72511:7;;;;;;;;:::i;:::-;;;;;;:27;-1:-1:-1;;;;;72511:27:0;;;-1:-1:-1;;;;;72511:27:0;;;;;72555:18;72545:4;72550:1;72545:7;;;;;;;;:::i;:::-;-1:-1:-1;;;;;72545:28:0;;;:7;;;;;;;;;:28;72632:21;;;;72582:89;;;;;72632:21;;;72582:89;;;10199:74:1;10289:18;;;10282:34;;;72582:41:0;;;;;;10172:18:1;;72582:89:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;72761:36:0;;;;;72791:4;72761:36;;;5955:74:1;72708:18:0;;72680;;-1:-1:-1;;;;;72761:21:0;;;;;5928:18:1;;72761:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;72828:21;;;;72975:16;;;;72828:194;;;;;72736:61;;-1:-1:-1;;;;;;72828:21:0;;;;:75;;:194;;72912:14;;72828:21;;72962:4;;72975:16;;73000:15;;72828:194;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;73076:16:0;;;;73054:39;;;;;-1:-1:-1;;;;;73076:16:0;;;73054:39;;;5955:74:1;73031:20:0;;73054:21;;;;;5928:18:1;;73054:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73113:16;;;;73102:63;;;;;-1:-1:-1;;;;;10217:55:1;;;73102:63:0;;;10199:74:1;10289:18;;;10282:34;;;73031:62:0;;-1:-1:-1;73113:16:0;;;73102:36;;10172:18:1;;73102:63:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;73211:16:0;;;;73174:103;;-1:-1:-1;;;;;;73174:28:0;;;;73211:16;73244:4;73258:12;73174:28;:103::i;:::-;73293:36;;;;;73323:4;73293:36;;;5955:74:1;73332:14:0;;-1:-1:-1;;;;;73293:21:0;;;;;5928:18:1;;73293:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:53;;;;:::i;:::-;73286:60;72219:1133;-1:-1:-1;;;;;;;;;72219:1133:0:o;68773:804::-;68868:19;;;:44;;-1:-1:-1;68891:21:0;;68868:44;68865:72;;;68773:804;;:::o;68865:72::-;69087:21;;19886:31;;69055:71;;69072:4;;-1:-1:-1;;;;;69087:21:0;69111:14;69055:8;:71::i;:::-;69133:14;;;;69164:21;;;;69133:72;;;;;-1:-1:-1;;;;;69164:21:0;;;69133:72;;;10199:74:1;10289:18;;;10282:34;;;69133:14:0;;;:22;;10172:18:1;;69133:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;69240:21:0;;;;69313:14;;;;69459:21;;;;69240:271;;;;;69291:4;69240:271;;;18159:34:1;-1:-1:-1;;;;;69313:14:0;;;18209:18:1;;;18202:43;18261:18;;;18254:34;;;18304:18;;;18297:34;;;69240:21:0;18347:19:1;;;18340:35;;;18391:19;;;18384:35;69459:21:0;;;18435:19:1;;;18428:44;69489:15:0;18488:19:1;;;18481:35;69240:21:0;;;:34;;18070:19:1;;69240:271:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;69525:46:0;;;19012:25:1;;;19068:2;19053:18;;19046:34;;;69525:46:0;;-1:-1:-1;18985:18:1;69525:46:0;18838:248:1;69583:281:0;69660:16;69680:1;69660:21;69657:49;;69583:281;:::o;69657:49::-;69819:20;;69791:14;;19886:31;;69791:67;;-1:-1:-1;;;;;69791:14:0;;;;69819:20;69841:16;69791:27;:67::i;81952:391::-;2230:30;82121:27;;;;;;;82118:220;;;82213:9;:26;;;82202:6;82179:20;82189:9;-1:-1:-1;;;;;62357:44:0;62334:7;62357:44;;;:35;:44;;;;;:52;;62269:146;82179:20;:29;;;;:::i;:::-;82178:61;;82177:112;;;-1:-1:-1;;;;;;58579:54:0;;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;58330:31;58579:63;;;;;;;;;;82244:45;82159:171;;;;-1:-1:-1;;;82159:171:0;;19293:2:1;82159:171:0;;;19275:21:1;19332:2;19312:18;;;19305:30;19371:21;19351:18;;;19344:49;19410:18;;82159:171:0;19091:343:1;82349:578:0;-1:-1:-1;;;;;82616:39:0;;82453:38;82616:39;;;:31;:39;;;;;;19886:31;;2230:30;;82616:39;;82613:309;;;82684:9;:30;;;82674:6;:40;;:84;;;-1:-1:-1;;;;;;58579:54:0;;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;58252:26;58579:63;;;;;;;;;;82718:40;82666:114;;;;-1:-1:-1;;;82666:114:0;;19641:2:1;82666:114:0;;;19623:21:1;19680:2;19660:18;;;19653:30;19719:19;19699:18;;;19692:47;19756:18;;82666:114:0;19439:341:1;82666:114:0;82613:309;;;82821:9;:30;;;82811:6;:40;;:81;;;-1:-1:-1;;;;;;58579:54:0;;58556:4;58579:54;;;1760:34;58579:54;;;;;;;;58252:26;58579:63;;;;;;;;;;82855:37;82803:111;;;;-1:-1:-1;;;82803:111:0;;19641:2:1;82803:111:0;;;19623:21:1;19680:2;19660:18;;;19653:30;19719:19;19699:18;;;19692:47;19756:18;;82803:111:0;19439:341:1;82933:321:0;2230:30;83144:31;;;;;;;83140:109;;83186:55;83223:6;83231:9;83186:36;:55::i;12586:195::-;12689:12;12721:52;12743:6;12751:4;12757:1;12760:12;12721:21;:52::i;:::-;12714:59;12586:195;-1:-1:-1;;;;12586:195:0:o;23766:205::-;23894:68;;-1:-1:-1;;;;;20066:15:1;;;23894:68:0;;;20048:34:1;20118:15;;20098:18;;;20091:43;20150:18;;;20143:34;;;23867:96:0;;23887:5;;23917:27;;19960:18:1;;23894:68:0;19785:398:1;83260:584:0;2230:30;83525:31;;19886;;2230:30;83525:31;;;;;83524:32;83516:76;;;;-1:-1:-1;;;83516:76:0;;20390:2:1;83516:76:0;;;20372:21:1;20429:2;20409:18;;;20402:30;20468:33;20448:18;;;20441:61;20519:18;;83516:76:0;20188:355:1;83516:76:0;83618:19;;;;-1:-1:-1;;;;;83605:32:0;;;83618:19;;83605:32;83604:77;;;;-1:-1:-1;;;;;;50574:29:0;;50550:4;50574:29;;;:12;;:29;:12;:29;;;;;83642:39;83601:238;;;83692:38;;83779:12;83739:37;;;:52;83800:31;;;;;;-1:-1:-1;;;83260:584:0:o;13638:530::-;13765:12;13823:5;13798:21;:30;;13790:81;;;;-1:-1:-1;;;13790:81:0;;20750:2:1;13790:81:0;;;20732:21:1;20789:2;20769:18;;;20762:30;20828:34;20808:18;;;20801:62;20899:8;20879:18;;;20872:36;20925:19;;13790:81:0;20548:402:1;13790:81:0;10035:20;;13882:60;;;;-1:-1:-1;;;13882:60:0;;21157:2:1;13882:60:0;;;21139:21:1;21196:2;21176:18;;;21169:30;21235:31;21215:18;;;21208:59;21284:18;;13882:60:0;20955:353:1;13882:60:0;14016:12;14030:23;14057:6;-1:-1:-1;;;;;14057:11:0;14077:5;14085:4;14057:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14015:75;;;;14108:52;14126:7;14135:10;14147:12;14108:17;:52::i;:::-;14101:59;13638:530;-1:-1:-1;;;;;;;13638:530:0:o;16178:742::-;16293:12;16322:7;16318:595;;;-1:-1:-1;16353:10:0;16346:17;;16318:595;16467:17;;:21;16463:439;;16730:10;16724:17;16791:15;16778:10;16774:2;16770:19;16763:44;16463:439;16873:12;16866:20;;-1:-1:-1;;;16866:20:0;;;;;;;;:::i;14:332:1:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;543:250;628:1;638:113;652:6;649:1;646:13;638:113;;;728:11;;;722:18;709:11;;;702:39;674:2;667:10;638:113;;;-1:-1:-1;;785:1:1;767:16;;760:27;543:250::o;798:455::-;947:2;936:9;929:21;910:4;979:6;973:13;1022:6;1017:2;1006:9;1002:18;995:34;1038:79;1110:6;1105:2;1094:9;1090:18;1085:2;1077:6;1073:15;1038:79;:::i;:::-;1169:2;1157:15;1174:66;1153:88;1138:104;;;;1244:2;1134:113;;798:455;-1:-1:-1;;798:455:1:o;1258:196::-;1326:20;;-1:-1:-1;;;;;1375:54:1;;1365:65;;1355:93;;1444:1;1441;1434:12;1355:93;1258:196;;;:::o;1459:254::-;1527:6;1535;1588:2;1576:9;1567:7;1563:23;1559:32;1556:52;;;1604:1;1601;1594:12;1556:52;1627:29;1646:9;1627:29;:::i;:::-;1617:39;1703:2;1688:18;;;;1675:32;;-1:-1:-1;;;1459:254:1:o;1900:184::-;1952:77;1949:1;1942:88;2049:4;2046:1;2039:15;2073:4;2070:1;2063:15;2089:1248;2182:6;2190;2243:2;2231:9;2222:7;2218:23;2214:32;2211:52;;;2259:1;2256;2249:12;2211:52;2282:29;2301:9;2282:29;:::i;:::-;2272:39;;2330:2;2383;2372:9;2368:18;2355:32;2406:18;2447:2;2439:6;2436:14;2433:34;;;2463:1;2460;2453:12;2433:34;2501:6;2490:9;2486:22;2476:32;;2546:7;2539:4;2535:2;2531:13;2527:27;2517:55;;2568:1;2565;2558:12;2517:55;2604:2;2591:16;2626:2;2622;2619:10;2616:36;;;2632:18;;:::i;:::-;2678:2;2675:1;2671:10;2710:2;2704:9;2769:66;2764:2;2760;2756:11;2752:84;2744:6;2740:97;2887:6;2875:10;2872:22;2867:2;2855:10;2852:18;2849:46;2846:72;;;2898:18;;:::i;:::-;2934:2;2927:22;2984:18;;;3018:15;;;;-1:-1:-1;3060:11:1;;;3056:20;;;3088:19;;;3085:39;;;3120:1;3117;3110:12;3085:39;3144:11;;;;3164:142;3180:6;3175:3;3172:15;3164:142;;;3246:17;;3234:30;;3197:12;;;;3284;;;;3164:142;;;3325:6;3315:16;;;;;;;;2089:1248;;;;;:::o;3342:328::-;3419:6;3427;3435;3488:2;3476:9;3467:7;3463:23;3459:32;3456:52;;;3504:1;3501;3494:12;3456:52;3527:29;3546:9;3527:29;:::i;:::-;3517:39;;3575:38;3609:2;3598:9;3594:18;3575:38;:::i;:::-;3565:48;;3660:2;3649:9;3645:18;3632:32;3622:42;;3342:328;;;;;:::o;3675:180::-;3734:6;3787:2;3775:9;3766:7;3762:23;3758:32;3755:52;;;3803:1;3800;3793:12;3755:52;-1:-1:-1;3826:23:1;;3675:180;-1:-1:-1;3675:180:1:o;4042:186::-;4101:6;4154:2;4142:9;4133:7;4129:23;4125:32;4122:52;;;4170:1;4167;4160:12;4122:52;4193:29;4212:9;4193:29;:::i;4233:254::-;4301:6;4309;4362:2;4350:9;4341:7;4337:23;4333:32;4330:52;;;4378:1;4375;4368:12;4330:52;4414:9;4401:23;4391:33;;4443:38;4477:2;4466:9;4462:18;4443:38;:::i;:::-;4433:48;;4233:254;;;;;:::o;4681:316::-;4758:6;4766;4774;4827:2;4815:9;4806:7;4802:23;4798:32;4795:52;;;4843:1;4840;4833:12;4795:52;-1:-1:-1;;4866:23:1;;;4936:2;4921:18;;4908:32;;-1:-1:-1;4987:2:1;4972:18;;;4959:32;;4681:316;-1:-1:-1;4681:316:1:o;5002:118::-;5088:5;5081:13;5074:21;5067:5;5064:32;5054:60;;5110:1;5107;5100:12;5125:241;5181:6;5234:2;5222:9;5213:7;5209:23;5205:32;5202:52;;;5250:1;5247;5240:12;5202:52;5289:9;5276:23;5308:28;5330:5;5308:28;:::i;5556:248::-;5624:6;5632;5685:2;5673:9;5664:7;5660:23;5656:32;5653:52;;;5701:1;5698;5691:12;5653:52;-1:-1:-1;;5724:23:1;;;5794:2;5779:18;;;5766:32;;-1:-1:-1;5556:248:1:o;6040:315::-;6105:6;6113;6166:2;6154:9;6145:7;6141:23;6137:32;6134:52;;;6182:1;6179;6172:12;6134:52;6205:29;6224:9;6205:29;:::i;:::-;6195:39;;6284:2;6273:9;6269:18;6256:32;6297:28;6319:5;6297:28;:::i;:::-;6344:5;6334:15;;;6040:315;;;;;:::o;6360:260::-;6428:6;6436;6489:2;6477:9;6468:7;6464:23;6460:32;6457:52;;;6505:1;6502;6495:12;6457:52;6528:29;6547:9;6528:29;:::i;:::-;6518:39;;6576:38;6610:2;6599:9;6595:18;6576:38;:::i;7345:437::-;7424:1;7420:12;;;;7467;;;7488:61;;7542:4;7534:6;7530:17;7520:27;;7488:61;7595:2;7587:6;7584:14;7564:18;7561:38;7558:218;;7632:77;7629:1;7622:88;7733:4;7730:1;7723:15;7761:4;7758:1;7751:15;7558:218;;7345:437;;;:::o;7787:184::-;7839:77;7836:1;7829:88;7936:4;7933:1;7926:15;7960:4;7957:1;7950:15;7976:128;8043:9;;;8064:11;;;8061:37;;;8078:18;;:::i;9361:125::-;9426:9;;;9447:10;;;9444:36;;;9460:18;;:::i;9836:184::-;9906:6;9959:2;9947:9;9938:7;9934:23;9930:32;9927:52;;;9975:1;9972;9965:12;9927:52;-1:-1:-1;9998:16:1;;9836:184;-1:-1:-1;9836:184:1:o;10327:245::-;10394:6;10447:2;10435:9;10426:7;10422:23;10418:32;10415:52;;;10463:1;10460;10453:12;10415:52;10495:9;10489:16;10514:28;10536:5;10514:28;:::i;11267:812::-;11678:25;11673:3;11666:38;11648:3;11733:6;11727:13;11749:75;11817:6;11812:2;11807:3;11803:12;11796:4;11788:6;11784:17;11749:75;:::i;:::-;11888:19;11883:2;11843:16;;;11875:11;;;11868:40;11933:13;;11955:76;11933:13;12017:2;12009:11;;12002:4;11990:17;;11955:76;:::i;:::-;12051:17;12070:2;12047:26;;11267:812;-1:-1:-1;;;;11267:812:1:o;12084:184::-;12136:77;12133:1;12126:88;12233:4;12230:1;12223:15;12257:4;12254:1;12247:15;13376:168;13449:9;;;13480;;13497:15;;;13491:22;;13477:37;13467:71;;13518:18;;:::i;13549:274::-;13589:1;13615;13605:189;;13650:77;13647:1;13640:88;13751:4;13748:1;13741:15;13779:4;13776:1;13769:15;13605:189;-1:-1:-1;13808:9:1;;13549:274::o;14481:196::-;14520:3;14548:5;14538:39;;14557:18;;:::i;:::-;-1:-1:-1;14604:66:1;14593:78;;14481:196::o;15799:184::-;15851:77;15848:1;15841:88;15948:4;15945:1;15938:15;15972:4;15969:1;15962:15;16391:1026;16653:4;16701:3;16690:9;16686:19;16732:6;16721:9;16714:25;16758:2;16796:6;16791:2;16780:9;16776:18;16769:34;16839:3;16834:2;16823:9;16819:18;16812:31;16863:6;16898;16892:13;16929:6;16921;16914:22;16967:3;16956:9;16952:19;16945:26;;17006:2;16998:6;16994:15;16980:29;;17027:1;17037:218;17051:6;17048:1;17045:13;17037:218;;;17116:13;;-1:-1:-1;;;;;17112:62:1;17100:75;;17230:15;;;;17195:12;;;;17073:1;17066:9;17037:218;;;-1:-1:-1;;;;;;;17311:55:1;;;;17306:2;17291:18;;17284:83;-1:-1:-1;;;17398:3:1;17383:19;17376:35;17272:3;16391:1026;-1:-1:-1;;;16391:1026:1:o;18527:306::-;18615:6;18623;18631;18684:2;18672:9;18663:7;18659:23;18655:32;18652:52;;;18700:1;18697;18690:12;18652:52;18729:9;18723:16;18713:26;;18779:2;18768:9;18764:18;18758:25;18748:35;;18823:2;18812:9;18808:18;18802:25;18792:35;;18527:306;;;;;:::o;21313:287::-;21442:3;21480:6;21474:13;21496:66;21555:6;21550:3;21543:4;21535:6;21531:17;21496:66;:::i;:::-;21578:16;;;;;21313:287;-1:-1:-1;;21313:287:1:o

Swarm Source

ipfs://d75d238657525e68e9d08d25dd50b1e59ddd7dacae9f874f06edab64b0261eae
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.