ETH Price: $3,582.85 (-3.02%)

Token

ERC-20: Lykke Corp Share (JANKA)
 

Overview

Max Total Supply

23,340,961 JANKA

Holders

93

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 0 Decimals)

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:
CMTAT

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MPL-2.0 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-01-29
*/

// File: openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol

// SPDX-License-Identifier: MPL-2.0
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 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");

        (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");

        (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");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal 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
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// File: openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

// File: openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol


// OpenZeppelin Contracts v4.4.1 (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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

// File: openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// File: openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol


// OpenZeppelin Contracts v4.4.1 (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 IERC20MetadataUpgradeable is IERC20Upgradeable {
    /**
     * @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: openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;




/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
        __ERC20_init_unchained(name_, symbol_);
    }

    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[45] private __gap;
}

// File: contracts/modules/BaseModule.sol



pragma solidity ^0.8.17;

// required OZ imports here


abstract contract BaseModule is Initializable, ERC20Upgradeable {
    /* Events */
    event Spend(address indexed owner, address indexed spender, uint256 amount);

    /* Variables */
    uint8 private _decimals;
    string public tokenId;
    string public terms;

    /* Initializers */
    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    function __Base_init(
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        string memory tokenId_,
        string memory terms_
    ) internal onlyInitializing {
        __ERC20_init(name_, symbol_);
        _decimals = decimals_;
        tokenId = tokenId_;
        terms = terms_;
    }

    function __Base_init_unchained(
        uint8 decimals_,
        string memory tokenId_,
        string memory terms_
    ) internal onlyInitializing {
        _decimals = decimals_;
        tokenId = tokenId_;
        terms = terms_;
    }

    /* Methods */
    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        bool result = super.transferFrom(sender, recipient, amount);
        if (result == true) {
            emit Spend(sender, _msgSender(), amount);
        }

        return result;
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(
        address spender,
        uint256 amount,
        uint256 currentAllowance
    ) public virtual returns (bool) {
        require(
            allowance(_msgSender(), spender) == currentAllowance,
            "CMTAT: current allowance is not right"
        );
        super.approve(spender, amount);
        return true;
    }

    uint256[50] private __gap;
}

// File: openzeppelin-contracts-upgradeable/contracts/access/IAccessControlUpgradeable.sol


// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControlUpgradeable {
    /**
     * @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 {AccessControl-_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 Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @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) external;

    /**
     * @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) external;

    /**
     * @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) external;
}

// File: openzeppelin-contracts-upgradeable/contracts/utils/StringsUpgradeable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library StringsUpgradeable {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @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] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// File: openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol


// OpenZeppelin Contracts v4.4.1 (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 IERC165Upgradeable {
    /**
     * @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-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol


// OpenZeppelin Contracts v4.4.1 (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 ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

// File: openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;





/**
 * @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 AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @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]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

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

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

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @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]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        StringsUpgradeable.toHexString(uint160(account), 20),
                        " is missing role ",
                        StringsUpgradeable.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 virtual 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.
     *
     * May emit a {RoleGranted} event.
     */
    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.
     *
     * May emit a {RoleRevoked} event.
     */
    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 revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    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.
     *
     * May emit a {RoleGranted} event.
     *
     * [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}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    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 {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

// File: contracts/modules/AuthorizationModule.sol



pragma solidity ^0.8.17;

abstract contract AuthorizationModule is AccessControlUpgradeable {}

// File: contracts/modules/BurnModule.sol



pragma solidity ^0.8.17;

abstract contract BurnModule is Initializable {
    bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

    event Burn(address indexed owner, uint256 amount);
}

// File: contracts/modules/MintModule.sol



pragma solidity ^0.8.17;

abstract contract MintModule {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    event Mint(address indexed beneficiary, uint256 amount);
}

// File: contracts/modules/EnforcementModule.sol



pragma solidity ^0.8.17;



/**
 * @dev Enforcement module.
 *
 * Allows the issuer to freeze transfers from a given address
 */
abstract contract EnforcementModule is
    Initializable,
    ContextUpgradeable,
    ERC20Upgradeable
{
    /**
     * @dev Emitted when an address is frozen.
     */
    event Freeze(address indexed enforcer, address indexed owner);

    /**
     * @dev Emitted when an address is unfrozen.
     */
    event Unfreeze(address indexed enforcer, address indexed owner);

    mapping(address => bool) private _frozen;

    bytes32 public constant ENFORCER_ROLE = keccak256("ENFORCER_ROLE");
    string internal constant TEXT_TRANSFER_REJECTED_FROZEN =
        "The address is frozen";

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Enforcement_init() internal onlyInitializing {
        __Context_init_unchained();
        __Enforcement_init_unchained();
    }

    function __Enforcement_init_unchained() internal onlyInitializing {}

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function frozen(address account) public view virtual returns (bool) {
        return _frozen[account];
    }

    /**
     * @dev Freezes an address.
     *
     */
    function _freeze(address account) internal virtual returns (bool) {
        if (_frozen[account]) return false;
        _frozen[account] = true;
        emit Freeze(_msgSender(), account);
        return true;
    }

    /**
     * @dev Unfreezes an address.
     *
     */
    function _unfreeze(address account) internal virtual returns (bool) {
        if (!_frozen[account]) return false;
        _frozen[account] = false;
        emit Unfreeze(_msgSender(), account);
        return true;
    }

    uint256[50] private __gap;
}

// File: openzeppelin-contracts-upgradeable/contracts/security/PausableUpgradeable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;


/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

// File: contracts/modules/PauseModule.sol



pragma solidity ^0.8.17;


/**
 * @dev ERC20 token with pausable token transfers, minting and burning.
 *
 * Useful for scenarios such as preventing trades until the end of an evaluation
 * period, or having an emergency switch for freezing all token transfers in the
 * event of a large bug.
 */
abstract contract PauseModule is Initializable, PausableUpgradeable {
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    string internal constant TEXT_TRANSFER_REJECTED_PAUSED =
        "All transfers paused";
}

// File: contracts/interfaces/IERC1404.sol



pragma solidity ^0.8.17;


interface IERC1404 {
    /**
     * @dev See ERC-1404
     *
     */
    function detectTransferRestriction(
        address _from,
        address _to,
        uint256 _amount
    ) external view returns (uint8);

    /**
     * @dev See ERC-1404
     *
     */
    function messageForTransferRestriction(uint8 _restrictionCode)
        external
        view
        returns (string memory);
}

// File: contracts/interfaces/IERC1404Wrapper.sol



pragma solidity ^0.8.17;

interface IERC1404Wrapper is IERC1404 {
    /**
     * @dev Returns true if the transfer is valid, and false otherwise.
     */
    function validateTransfer(
        address _from,
        address _to,
        uint256 _amount
    ) external view returns (bool isValid);
}

// File: contracts/interfaces/IRule.sol



pragma solidity ^0.8.17;

interface IRule is IERC1404Wrapper {
     /**
     * @dev Returns true if the restriction code exists, and false otherwise.
     */
     function canReturnTransferRestrictionCode(uint8 _restrictionCode)
        external
        view
        returns (bool);
}

// File: contracts/interfaces/IRuleEngine.sol



pragma solidity ^0.8.17;


interface IRuleEngine is IERC1404Wrapper{
    /**
    * @dev define the rules, the precedent rules will be overwritten
    */
    function setRules(IRule[] calldata rules_) external;

    /**
    * @dev return the number of rules
    */
    function ruleLength() external view returns (uint256);

    /**
    * @dev return the rule at the index specified by ruleId
    */
    function rule(uint256 ruleId) external view returns (IRule);

    /**
    * @dev return all the rules
    */
    function rules() external view returns (IRule[] memory);
}

// File: contracts/modules/ValidationModule.sol



pragma solidity ^0.8.17;



/**
 * @dev Validation module.
 *
 * Useful for to restrict and validate transfers
 */
abstract contract ValidationModule is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when a rule engine is set.
     */
    event RuleEngineSet(address indexed newRuleEngine);

    IRuleEngine public ruleEngine;

    /**
     * @dev Initializes the contract with rule engine.
     */
    function __Validation_init(IRuleEngine ruleEngine_) internal onlyInitializing {
        __Context_init_unchained();
        __Validation_init_unchained(ruleEngine_);
    }

    function __Validation_init_unchained(IRuleEngine ruleEngine_)
        internal
        onlyInitializing
    {
        if (address(ruleEngine_) != address(0)) {
            ruleEngine = ruleEngine_;
            emit RuleEngineSet(address(ruleEngine));
        }
    }

    function _validateTransfer(
        address from,
        address to,
        uint256 amount
    ) internal view returns (bool) {
        return ruleEngine.validateTransfer(from, to, amount);
    }

    function _messageForTransferRestriction(uint8 restrictionCode)
        internal
        view
        returns (string memory)
    {
        return ruleEngine.messageForTransferRestriction(restrictionCode);
    }

    function _detectTransferRestriction(
        address from,
        address to,
        uint256 amount
    ) internal view returns (uint8) {
        return ruleEngine.detectTransferRestriction(from, to, amount);
    }

    uint256[50] private __gap;
}

// File: openzeppelin-contracts-upgradeable/contracts/metatx/ERC2771ContextUpgradeable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.9;


/**
 * @dev Context variant with ERC2771 support.
 */
abstract contract ERC2771ContextUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable _trustedForwarder;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(address trustedForwarder) {
        _trustedForwarder = trustedForwarder;
    }

    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
        return forwarder == _trustedForwarder;
    }

    function _msgSender() internal view virtual override returns (address sender) {
        if (isTrustedForwarder(msg.sender)) {
            // The assembly code is more direct than the Solidity version using `abi.decode`.
            /// @solidity memory-safe-assembly
            assembly {
                sender := shr(96, calldataload(sub(calldatasize(), 20)))
            }
        } else {
            return super._msgSender();
        }
    }

    function _msgData() internal view virtual override returns (bytes calldata) {
        if (isTrustedForwarder(msg.sender)) {
            return msg.data[:msg.data.length - 20];
        } else {
            return super._msgData();
        }
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

// File: contracts/modules/MetaTxModule.sol



pragma solidity ^0.8.17;

/**
 * @dev Meta transaction (gasless) module.
 *
 * Useful for to provide UX where the user does not pay gas for token exchange
 */
abstract contract MetaTxModule is ERC2771ContextUpgradeable {
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(address trustedForwarder)
        ERC2771ContextUpgradeable(trustedForwarder)
    {
        // TODO : Emit an event ?
        // See : https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/mocks/ERC2771ContextMockUpgradeable.sol
        // emit Sender(_msgSender());
    }
}

// File: openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUpgradeable {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @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.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`.
        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
        // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
        // good first aproximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1;
        uint256 x = a;
        if (x >> 128 > 0) {
            x >>= 128;
            result <<= 64;
        }
        if (x >> 64 > 0) {
            x >>= 64;
            result <<= 32;
        }
        if (x >> 32 > 0) {
            x >>= 32;
            result <<= 16;
        }
        if (x >> 16 > 0) {
            x >>= 16;
            result <<= 8;
        }
        if (x >> 8 > 0) {
            x >>= 8;
            result <<= 4;
        }
        if (x >> 4 > 0) {
            x >>= 4;
            result <<= 2;
        }
        if (x >> 2 > 0) {
            result <<= 1;
        }

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        uint256 result = sqrt(a);
        if (rounding == Rounding.Up && result * result < a) {
            result += 1;
        }
        return result;
    }
}

// File: openzeppelin-contracts-upgradeable/contracts/utils/ArraysUpgradeable.sol


// OpenZeppelin Contracts v4.4.1 (utils/Arrays.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to array types.
 */
library ArraysUpgradeable {
    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * `array` is expected to be sorted in ascending order, and to contain no
     * repeated elements.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        if (array.length == 0) {
            return 0;
        }

        uint256 low = 0;
        uint256 high = array.length;

        while (low < high) {
            uint256 mid = MathUpgradeable.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds down (it does integer division with truncation).
            if (array[mid] > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && array[low - 1] == element) {
            return low - 1;
        } else {
            return low;
        }
    }
}

// File: contracts/modules/SnapshotModule.sol



pragma solidity ^0.8.17;




/**
 * @dev Snapshot module.
 *
 * Useful to take a snapshot of token holder balance and total supply at a specific time
 */

abstract contract SnapshotModule is
    Initializable,
    ContextUpgradeable,
    ERC20Upgradeable
{
    using ArraysUpgradeable for uint256[];

    event SnapshotSchedule(uint256 indexed oldTime, uint256 indexed newTime);
    event SnapshotUnschedule(uint256 indexed time);

    struct Snapshots {
        uint256[] ids;
        uint256[] values;
    }

    bytes32 public constant SNAPSHOOTER_ROLE = keccak256("SNAPSHOOTER_ROLE");
    mapping(address => Snapshots) private _accountBalanceSnapshots;
    Snapshots private _totalSupplySnapshots;

    uint256 private _currentSnapshot;

    uint256[] private _scheduledSnapshots;

    function __Snapshot_init() internal onlyInitializing {
        __Context_init_unchained();
        __Snapshot_init_unchained();
    }

    function __Snapshot_init_unchained() internal onlyInitializing{
        _currentSnapshot = 0;
    }

    function _scheduleSnapshot(uint256 time) internal {
        require(block.timestamp < time, "Snapshot scheduled in the past");
        (bool found, ) = _findScheduledSnapshotIndex(time);
        require(!found, "Snapshot already scheduled for this time");
        _scheduledSnapshots.push(time);
        emit SnapshotSchedule(0, time);
    }

    function _rescheduleSnapshot(uint256 oldTime, uint256 newTime)
        internal
    {
        require(block.timestamp < oldTime, "Snapshot already done");
        require(block.timestamp < newTime, "Snapshot scheduled in the past");

        (bool foundNew, ) = _findScheduledSnapshotIndex(newTime);
        require(!foundNew, "Snapshot already scheduled for this time");

        (bool foundOld, uint256 index) = _findScheduledSnapshotIndex(oldTime);
        require(foundOld, "Snapshot not found");

        _scheduledSnapshots[index] = newTime;

        emit SnapshotSchedule(oldTime, newTime);
    }

    function _unscheduleSnapshot(uint256 time) internal {
        require(block.timestamp < time, "Snapshot already done");
        (bool found, uint256 index) = _findScheduledSnapshotIndex(time);
        require(found, "Snapshot not found");

        _removeScheduledItem(index);

        emit SnapshotUnschedule(time);
    }

    function getNextSnapshots() public view returns (uint256[] memory) {
        return _scheduledSnapshots;
    }

    function snapshotBalanceOf(uint256 time, address owner)
        public
        view
        returns (uint256)
    {
        (bool snapshotted, uint256 value) = _valueAt(
            time,
            _accountBalanceSnapshots[owner]
        );

        return snapshotted ? value : balanceOf(owner);
    }

    function snapshotTotalSupply(uint256 time) public view returns (uint256) {
        (bool snapshotted, uint256 value) = _valueAt(
            time,
            _totalSupplySnapshots
        );

        return snapshotted ? value : totalSupply();
    }

    // Update balance and/or total supply snapshots before the values are modified. This is implemented
    // in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations.
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, amount);

        _setCurrentSnapshot();
        if (from != address(0)) {
            // for both burn and transfer
            _updateAccountSnapshot(from);
            if (to != address(0)) {
                // transfer
                _updateAccountSnapshot(to);
            } else {
                // burn
                _updateTotalSupplySnapshot();
            }
        } else {
            // mint
            _updateAccountSnapshot(to);
            _updateTotalSupplySnapshot();
        }
    }

    function _valueAt(uint256 time, Snapshots storage snapshots)
        private
        view
        returns (bool, uint256)
    {
        // When a valid snapshot is queried, there are three possibilities:
        //  a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never
        //  created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds
        //  to this id is the current one.
        //  b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the
        //  requested id, and its value is the one to return.
        //  c) More snapshots were created after the requested one, and the queried value was later modified. There will be
        //  no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is
        //  larger than the requested one.
        //
        // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if
        // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does
        // exactly this.

        uint256 index = snapshots.ids.findUpperBound(time);

        if (index == snapshots.ids.length) {
            return (false, 0);
        } else {
            return (true, snapshots.values[index]);
        }
    }

    function _updateAccountSnapshot(address account) private {
        _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account));
    }

    function _updateTotalSupplySnapshot() private {
        _updateSnapshot(_totalSupplySnapshots, totalSupply());
    }

    function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue)
        private
    {
        uint256 current = _getCurrentSnapshot();
        if (_lastSnapshot(snapshots.ids) < current) {
            snapshots.ids.push(current);
            snapshots.values.push(currentValue);
        }
    }

    function _setCurrentSnapshot() internal {
        uint256 time = _findScheduledMostRecentPastSnapshot();
        if (time > 0) {
            _currentSnapshot = time;
            _clearPastScheduled();
        }
    }

    function _getCurrentSnapshot() internal view virtual returns (uint256) {
        return _currentSnapshot;
    }

    function _lastSnapshot(uint256[] storage ids)
        private
        view
        returns (uint256)
    {
        if (ids.length == 0) {
            return 0;
        } else {
            return ids[ids.length - 1];
        }
    }

    function _findScheduledSnapshotIndex(uint256 time)
        private
        view
        returns (bool, uint256)
    {
        for (uint256 i = 0; i < _scheduledSnapshots.length; i++) {
            if (_scheduledSnapshots[i] == time) {
                return (true, i);
            }
        }
        return (false, 0);
    }

    function _findScheduledMostRecentPastSnapshot()
        private
        view
        returns (uint256)
    {
        if (_scheduledSnapshots.length == 0) return 0;
        uint256 mostRecent = 0;
        for (uint256 i = 0; i < _scheduledSnapshots.length; i++) {
            if (
                _scheduledSnapshots[i] <= block.timestamp &&
                _scheduledSnapshots[i] > mostRecent
            ) {
                mostRecent = _scheduledSnapshots[i];
            }
        }
        return mostRecent;
    }

    function _clearPastScheduled() private {
        uint256 i = 0;
        while (i < _scheduledSnapshots.length) {
            if (_scheduledSnapshots[i] <= block.timestamp) {
                _removeScheduledItem(i);
            } else {
                i += 1;
            }
        }
    }

    function _removeScheduledItem(uint256 index) private {
        _scheduledSnapshots[index] = _scheduledSnapshots[
            _scheduledSnapshots.length - 1
        ];
        _scheduledSnapshots.pop();
    }

    uint256[50] private __gap;
}

// File: contracts/CMTAT.sol



pragma solidity ^0.8.17;

// required OZ imports here













contract CMTAT is
    Initializable,
    ContextUpgradeable,
    BaseModule,
    AuthorizationModule,
    PauseModule,
    MintModule,
    BurnModule,
    EnforcementModule,
    ValidationModule,
    MetaTxModule,
    SnapshotModule
{
    enum REJECTED_CODE { TRANSFER_OK, TRANSFER_REJECTED_PAUSED, TRANSFER_REJECTED_FROZEN }
    string constant TEXT_TRANSFER_OK = "No restriction";
    event TermSet(string indexed newTerm);
    event TokenIdSet(string indexed newTokenId);

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(
        address forwarder
    ) MetaTxModule(forwarder) {
    }

    function initialize(
        address owner,
        string memory name,
        string memory symbol,
        string memory tokenId,
        string memory terms
    ) public initializer {
        __CMTAT_init(owner, name, symbol, tokenId, terms);
    }

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
     * account that deploys the contract.
     *
     * See {ERC20-constructor}.
     */
    function __CMTAT_init(
        address owner,
        string memory name,
        string memory symbol,
        string memory tokenId,
        string memory terms
    ) internal onlyInitializing {
        __Context_init_unchained();
        __Base_init_unchained(0, tokenId, terms);
        __AccessControl_init_unchained();
        __ERC20_init_unchained(name, symbol);
        __Pausable_init_unchained();
        __Enforcement_init_unchained();
        __Snapshot_init_unchained();
        __CMTAT_init_unchained(owner);
    }

    function __CMTAT_init_unchained(address owner) internal onlyInitializing {
        _setupRole(DEFAULT_ADMIN_ROLE, owner);
        _setupRole(ENFORCER_ROLE, owner);
        _setupRole(MINTER_ROLE, owner);
        _setupRole(BURNER_ROLE, owner);
        _setupRole(PAUSER_ROLE, owner);
        _setupRole(SNAPSHOOTER_ROLE, owner);
    }

    /**
     * @dev Creates `amount` new tokens for `to`.
     *
     * See {ERC20-_mint}.
     *
     * Requirements:
     *
     * - the caller must have the `MINTER_ROLE`.
     */
    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
        _mint(to, amount);
        emit Mint(to, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount)
        public
        onlyRole(BURNER_ROLE)
    {
        uint256 currentAllowance = allowance(account, _msgSender());
        require(
            currentAllowance >= amount,
            "CMTAT: burn amount exceeds allowance"
        );
        unchecked {
            _approve(account, _msgSender(), currentAllowance - amount);
        }
        _burn(account, amount);
        emit Burn(account, amount);
    }

    /**
     * @dev Pauses all token transfers.
     *
     * See {ERC20Pausable} and {Pausable-_pause}.
     *
     * Requirements:
     *
     * - the caller must have the `PAUSER_ROLE`.
     */
    function pause() public onlyRole(PAUSER_ROLE) {
        _pause();
    }

    /**
     * @dev Unpauses all token transfers.
     *
     * See {ERC20Pausable} and {Pausable-_unpause}.
     *
     * Requirements:
     *
     * - the caller must have the `PAUSER_ROLE`.
     */
    function unpause() public onlyRole(PAUSER_ROLE) {
        _unpause();
    }

    /**
     * @dev Freezes an address.
     *
     */
    function freeze(address account)
        public
        onlyRole(ENFORCER_ROLE)
        returns (bool)
    {
        return _freeze(account);
    }

    /**
     * @dev Unfreezes an address.
     *
     */
    function unfreeze(address account)
        public
        onlyRole(ENFORCER_ROLE)
        returns (bool)
    {
        return _unfreeze(account);
    }

    function decimals()
        public
        view
        virtual
        override(ERC20Upgradeable, BaseModule)
        returns (uint8)
    {
        return super.decimals();
    }

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override(ERC20Upgradeable, BaseModule) returns (bool) {
        return super.transferFrom(sender, recipient, amount);
    }

    /**
     * @dev ERC1404 check if _value token can be transferred from _from to _to
     * @param from address The address which you want to send tokens from
     * @param to address The address which you want to transfer to
     * @param amount uint256 the amount of tokens to be transferred
     * @return code of the rejection reason
     */
    function detectTransferRestriction(
        address from,
        address to,
        uint256 amount
    ) public view returns (uint8 code) {
        if (paused()) {
            return uint8(REJECTED_CODE.TRANSFER_REJECTED_PAUSED);
        } else if (frozen(from)) {
            return uint8(REJECTED_CODE.TRANSFER_REJECTED_FROZEN);
        } else if (address(ruleEngine) != address(0)) {
            return _detectTransferRestriction(from, to, amount);
        }
        return uint8(REJECTED_CODE.TRANSFER_OK);
    }

    /**
     * @dev ERC1404 returns the human readable explaination corresponding to the error code returned by detectTransferRestriction
     * @param restrictionCode The error code returned by detectTransferRestriction
     * @return message The human readable explaination corresponding to the error code returned by detectTransferRestriction
     */
    function messageForTransferRestriction(uint8 restrictionCode)
        external
        view
        returns (string memory message)
    {
        if (restrictionCode == uint8(REJECTED_CODE.TRANSFER_OK)) {
            return TEXT_TRANSFER_OK;
        } else if (restrictionCode == uint8(REJECTED_CODE.TRANSFER_REJECTED_PAUSED)) {
            return TEXT_TRANSFER_REJECTED_PAUSED;
        } else if (restrictionCode == uint8(REJECTED_CODE.TRANSFER_REJECTED_FROZEN)) {
            return TEXT_TRANSFER_REJECTED_FROZEN;
        } else if (address(ruleEngine) != address(0)) {
            return _messageForTransferRestriction(restrictionCode);
        }
    }

    function scheduleSnapshot(uint256 time)
        public
        onlyRole(SNAPSHOOTER_ROLE)
    {
        _scheduleSnapshot(time);
    }

    function rescheduleSnapshot(uint256 oldTime, uint256 newTime)
        public
        onlyRole(SNAPSHOOTER_ROLE)
    {
        _rescheduleSnapshot(oldTime, newTime);
    }

    function unscheduleSnapshot(uint256 time)
        public
        onlyRole(SNAPSHOOTER_ROLE)
    {
        _unscheduleSnapshot(time);
    }

    function setTokenId(string memory tokenId_)
        public
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        tokenId = tokenId_;
        emit TokenIdSet(tokenId_);
    }

    function setTerms(string memory terms_)
        public
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        terms = terms_;
        emit TermSet(terms_);
    }

    /// @custom:oz-upgrades-unsafe-allow selfdestruct
    function kill() public onlyRole(DEFAULT_ADMIN_ROLE) {
        selfdestruct(payable(_msgSender()));
    }

    function setRuleEngine(IRuleEngine ruleEngine_)
        external
        onlyRole(DEFAULT_ADMIN_ROLE)
    {
        ruleEngine = ruleEngine_;
        emit RuleEngineSet(address(ruleEngine_));
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal override(SnapshotModule, ERC20Upgradeable) {
        require(!paused(), "CMTAT: token transfer while paused");
        require(!frozen(from), "CMTAT: token transfer while frozen");

        super._beforeTokenTransfer(from, to, amount);

        if (address(ruleEngine) != address(0)) {
            require(
                _validateTransfer(from, to, amount),
                "CMTAT: transfer rejected by validation module"
            );
        }
    }

    function _msgSender()
        internal
        view
        override(ERC2771ContextUpgradeable, ContextUpgradeable)
        returns (address sender)
    {
        return super._msgSender();
    }

    function _msgData()
        internal
        view
        override(ERC2771ContextUpgradeable, ContextUpgradeable)
        returns (bytes calldata)
    {
        return super._msgData();
    }

    uint256[50] private __gap;
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"enforcer","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Freeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","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":true,"internalType":"address","name":"newRuleEngine","type":"address"}],"name":"RuleEngineSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldTime","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newTime","type":"uint256"}],"name":"SnapshotSchedule","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"time","type":"uint256"}],"name":"SnapshotUnschedule","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":"amount","type":"uint256"}],"name":"Spend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"newTerm","type":"string"}],"name":"TermSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"newTokenId","type":"string"}],"name":"TokenIdSet","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"enforcer","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Unfreeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BURNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENFORCER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SNAPSHOOTER_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":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"currentAllowance","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":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"detectTransferRestriction","outputs":[{"internalType":"uint8","name":"code","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"freeze","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextSnapshots","outputs":[{"internalType":"uint256[]","name":"","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":"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":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"tokenId","type":"string"},{"internalType":"string","name":"terms","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"restrictionCode","type":"uint8"}],"name":"messageForTransferRestriction","outputs":[{"internalType":"string","name":"message","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"oldTime","type":"uint256"},{"internalType":"uint256","name":"newTime","type":"uint256"}],"name":"rescheduleSnapshot","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":[],"name":"ruleEngine","outputs":[{"internalType":"contract IRuleEngine","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"name":"scheduleSnapshot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRuleEngine","name":"ruleEngine_","type":"address"}],"name":"setRuleEngine","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"terms_","type":"string"}],"name":"setTerms","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"tokenId_","type":"string"}],"name":"setTokenId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"snapshotBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"name":"snapshotTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[],"name":"terms","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","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"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unfreeze","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"name":"unscheduleSnapshot","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b50604051620033aa380380620033aa833981016040819052620000349162000046565b6001600160a01b031660805262000078565b6000602082840312156200005957600080fd5b81516001600160a01b03811681146200007157600080fd5b9392505050565b60805161330f6200009b6000396000818161044a0152611f65015261330f6000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806378f86afc11610182578063b6dbcae5116100e9578063d547741f116100a2578063e20c35e51161007c578063e20c35e51461067a578063e63ab1e91461068d578063fb78ed40146106a2578063fcf196b4146106b757600080fd5b8063d547741f14610641578063dcfd616f14610654578063dd62ed3e1461066757600080fd5b8063b6dbcae5146105ac578063d0516650146105bf578063d21268ef146105ec578063d4ce1415146105ff578063d502562514610612578063d53913931461061a57600080fd5b806395d89b411161013b57806395d89b4114610550578063a217fddf14610558578063a312e15514610560578063a457c2d714610573578063a4a0a30114610586578063a9059cbb1461059957600080fd5b806378f86afc146104e957806379cc6790146104fc5780637f4ab1dd1461050f5780638456cb59146105225780638d1fdf2f1461052a57806391d148541461053d57600080fd5b80633950935111610226578063572b6c05116101df578063572b6c051461043a5780635c975abb1461047a5780635ee7a94214610485578063634daf76146104985780636439fd75146104ab57806370a08231146104c057600080fd5b806339509351146103de5780633f4ba83a146103f157806340c10f19146103f957806341c0e1b51461040c578063426a84931461041457806345c8b1a61461042757600080fd5b8063246b72ec11610278578063246b72ec1461033d578063248a9ca314610352578063282c51f3146103755780632f2ff15d1461039c578063313ce567146103b157806336568abe146103cb57600080fd5b806301ffc9a7146102c057806306fdde03146102e8578063095ea7b3146102fd57806317d70f7c1461031057806318160ddd1461031857806323b872dd1461032a575b600080fd5b6102d36102ce366004612a85565b6106e3565b60405190151581526020015b60405180910390f35b6102f061071a565b6040516102df9190612ad3565b6102d361030b366004612b1b565b6107ac565b6102f06107ce565b6035545b6040519081526020016102df565b6102d3610338366004612b47565b61085c565b61031c60008051602061329a83398151915281565b61031c610360366004612b88565b600090815260cc602052604090206001015490565b61031c7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b6103af6103aa366004612ba1565b610873565b005b6103b961089d565b60405160ff90911681526020016102df565b6103af6103d9366004612ba1565b6108b0565b6102d36103ec366004612b1b565b610943565b6103af61096f565b6103af610407366004612b1b565b610992565b6103af610a0e565b6102d3610422366004612bd1565b610a2c565b6102d3610435366004612c06565b610ab0565b6102d3610448366004612c06565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b60fe5460ff166102d3565b61031c610493366004612b88565b610adc565b61031c6104a6366004612ba1565b610b08565b61031c6000805160206132ba83398151915281565b61031c6104ce366004612c06565b6001600160a01b031660009081526033602052604090205490565b6103af6104f7366004612ce8565b610b62565b6103af61050a366004612b1b565b610bbc565b6102f061051d366004612d2c565b610cb9565b6103af610d86565b6102d3610538366004612c06565b610da6565b6102d361054b366004612ba1565b610dc9565b6102f0610df4565b61031c600081565b6103af61056e366004612b88565b610e03565b6102d3610581366004612b1b565b610e24565b6103af610594366004612c06565b610eaa565b6102d36105a7366004612b1b565b610f01565b6103af6105ba366004612d49565b610f19565b6102d36105cd366004612c06565b6001600160a01b03166000908152610130602052604090205460ff1690565b6103af6105fa366004612e09565b611034565b6103b961060d366004612b47565b611056565b6102f06110c0565b61031c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6103af61064f366004612ba1565b6110cd565b6103af610662366004612ce8565b6110f2565b61031c610675366004612e2b565b61114c565b6103af610688366004612b88565b611177565b61031c60008051602061327a83398151915281565b6106aa611198565b6040516102df9190612e59565b610163546106cb906001600160a01b031681565b6040516001600160a01b0390911681526020016102df565b60006001600160e01b03198216637965db0b60e01b148061071457506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606036805461072990612e9d565b80601f016020809104026020016040519081016040528092919081815260200182805461075590612e9d565b80156107a25780601f10610777576101008083540402835291602001916107a2565b820191906000526020600020905b81548152906001019060200180831161078557829003601f168201915b5050505050905090565b6000806107b76111f0565b90506107c48185856111fa565b5060019392505050565b606680546107db90612e9d565b80601f016020809104026020016040519081016040528092919081815260200182805461080790612e9d565b80156108545780601f1061082957610100808354040283529160200191610854565b820191906000526020600020905b81548152906001019060200180831161083757829003601f168201915b505050505081565b600061086984848461131e565b90505b9392505050565b600082815260cc602052604090206001015461088e81611394565b61089883836113a5565b505050565b60006108ab60655460ff1690565b905090565b6108b86111f0565b6001600160a01b0316816001600160a01b0316146109355760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b61093f828261142c565b5050565b60008061094e6111f0565b90506107c4818585610960858961114c565b61096a9190612ee7565b6111fa565b60008051602061327a83398151915261098781611394565b61098f6114b1565b50565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66109bc81611394565b6109c68383611509565b826001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688583604051610a0191815260200190565b60405180910390a2505050565b6000610a1981611394565b610a216111f0565b6001600160a01b0316ff5b600081610a40610a3a6111f0565b8661114c565b14610a9b5760405162461bcd60e51b815260206004820152602560248201527f434d5441543a2063757272656e7420616c6c6f77616e6365206973206e6f74206044820152641c9a59da1d60da1b606482015260840161092c565b610aa584846107ac565b506001949350505050565b60006000805160206132ba833981519152610aca81611394565b610ad3836115f4565b91505b50919050565b6000806000610aed846101c9611683565b9150915081610afe57603554610b00565b805b949350505050565b6001600160a01b03811660009081526101c86020526040812081908190610b30908690611683565b9150915081610b57576001600160a01b038416600090815260336020526040902054610b59565b805b95945050505050565b6000610b6d81611394565b6067610b798382612f40565b5081604051610b889190613000565b604051908190038120907f04ad91be0cc2638e10a8fa52bb61221dcf70dfcd07e6beae6b0d5a3f75070fcf90600090a25050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848610be681611394565b6000610bf4846106756111f0565b905082811015610c525760405162461bcd60e51b8152602060048201526024808201527f434d5441543a206275726e20616d6f756e74206578636565647320616c6c6f77604482015263616e636560e01b606482015260840161092c565b610c6684610c5e6111f0565b8584036111fa565b610c7084846116d8565b836001600160a01b03167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca584604051610cab91815260200190565b60405180910390a250505050565b606060ff8216610ced57505060408051808201909152600e81526d2737903932b9ba3934b1ba34b7b760911b602082015290565b60001960ff831601610d29575050604080518082019091526014815273105b1b081d1c985b9cd9995c9cc81c185d5cd95960621b602082015290565b60011960ff831601610d665750506040805180820190915260158152742a34329030b2323932b9b99034b990333937bd32b760591b602082015290565b610163546001600160a01b031615610d815761071482611832565b919050565b60008051602061327a833981519152610d9e81611394565b61098f6118a7565b60006000805160206132ba833981519152610dc081611394565b610ad3836118e5565b600091825260cc602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60606037805461072990612e9d565b60008051602061329a833981519152610e1b81611394565b61093f82611978565b600080610e2f6111f0565b90506000610e3d828661114c565b905083811015610e9d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161092c565b610aa582868684036111fa565b6000610eb581611394565b61016380546001600160a01b0319166001600160a01b0384169081179091556040517f9c4d5c11b88d1e3d9c7ad50900cb6d10ac72853248cdc85ca868fb772e62b44990600090a25050565b600080610f0c6111f0565b90506107c4818585611a57565b600054610100900460ff1615808015610f395750600054600160ff909116105b80610f535750303b158015610f53575060005460ff166001145b610fb65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161092c565b6000805460ff191660011790558015610fd9576000805461ff0019166101001790555b610fe68686868686611c32565b801561102c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b60008051602061329a83398151915261104c81611394565b6108988383611ca7565b600061106460fe5460ff1690565b156110735760015b905061086c565b6001600160a01b0384166000908152610130602052604090205460ff161561109c57600261106c565b610163546001600160a01b0316156110b95761106c848484611e10565b6000610869565b606780546107db90612e9d565b600082815260cc60205260409020600101546110e881611394565b610898838361142c565b60006110fd81611394565b60666111098382612f40565b50816040516111189190613000565b604051908190038120907f1a3f197f2cb06b445ad0c131c52bc822947dae771f49d55fbd17bb6e462254bd90600090a25050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60008051602061329a83398151915261118f81611394565b61093f82611e8f565b60606101cc8054806020026020016040519081016040528092919081815260200182805480156107a257602002820191906000526020600020905b8154815260200190600101908083116111d3575050505050905090565b60006108ab611f61565b6001600160a01b03831661125c5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161092c565b6001600160a01b0382166112bd5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161092c565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60008061132c858585611fa5565b9050801515600103610869576113406111f0565b6001600160a01b0316856001600160a01b03167f7c2b9369bf4a6bd9745889c658ad00a4d57e280c4c80fa1c74db2a9e52c136358560405161138491815260200190565b60405180910390a3949350505050565b61098f816113a06111f0565b611fc8565b6113af8282610dc9565b61093f57600082815260cc602090815260408083206001600160a01b03851684529091529020805460ff191660011790556113e86111f0565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6114368282610dc9565b1561093f57600082815260cc602090815260408083206001600160a01b03851684529091529020805460ff1916905561146d6111f0565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6114b961202c565b60fe805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6114ec6111f0565b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03821661155f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161092c565b61156b60008383612077565b806035600082825461157d9190612ee7565b90915550506001600160a01b038216600090815260336020526040812080548392906115aa908490612ee7565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b0381166000908152610130602052604081205460ff1661161d57506000919050565b6001600160a01b038216600081815261013060205260409020805460ff191690556116466111f0565b6001600160a01b03167f4f3ab9ff0cc4f039268532098e01239544b0420171876e36889d01c62c784c7960405160405180910390a3506001919050565b6000808061169184866121d4565b845490915081036116a95760008092509250506116d1565b60018460010182815481106116c0576116c061301c565b906000526020600020015492509250505b9250929050565b6001600160a01b0382166117385760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161092c565b61174482600083612077565b6001600160a01b038216600090815260336020526040902054818110156117b85760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161092c565b6001600160a01b03831660009081526033602052604081208383039055603580548492906117e7908490613032565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b61016354604051637f4ab1dd60e01b815260ff831660048201526060916001600160a01b031690637f4ab1dd90602401600060405180830381865afa15801561187f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107149190810190613045565b6118af612299565b60fe805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114ec6111f0565b6001600160a01b0381166000908152610130602052604081205460ff161561190f57506000919050565b6001600160a01b038216600081815261013060205260409020805460ff1916600117905561193b6111f0565b6001600160a01b03167f51d18786e9cb144f87d46e7b796309ea84c7c687d91e09c97f051eacf59bc52860405160405180910390a3506001919050565b8042106119c75760405162461bcd60e51b815260206004820152601e60248201527f536e617073686f74207363686564756c656420696e2074686520706173740000604482015260640161092c565b60006119d2826122df565b50905080156119f35760405162461bcd60e51b815260040161092c906130b3565b6101cc805460018101825560009182527f9a37fbd5e796e9046c2f5f7e29046a230a4ba9ada48a80535ed93a51fec5cfbc018390556040518391907fe2ad3b1abe53383dbe6359f02f11ae76d91cfab321b37083b16e1d96a81d4183908290a35050565b6001600160a01b038316611abb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161092c565b6001600160a01b038216611b1d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161092c565b611b28838383612077565b6001600160a01b03831660009081526033602052604090205481811015611ba05760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161092c565b6001600160a01b03808516600090815260336020526040808220858503905591851681529081208054849290611bd7908490612ee7565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611c2391815260200190565b60405180910390a35b50505050565b600054610100900460ff16611c595760405162461bcd60e51b815260040161092c906130fb565b611c6161233e565b611c6d60008383612365565b611c7561233e565b611c7f84846123b4565b611c876123f4565b611c8f61233e565b611c97612427565b611ca085612456565b5050505050565b814210611cee5760405162461bcd60e51b8152602060048201526015602482015274536e617073686f7420616c726561647920646f6e6560581b604482015260640161092c565b804210611d3d5760405162461bcd60e51b815260206004820152601e60248201527f536e617073686f74207363686564756c656420696e2074686520706173740000604482015260640161092c565b6000611d48826122df565b5090508015611d695760405162461bcd60e51b815260040161092c906130b3565b600080611d75856122df565b9150915081611dbb5760405162461bcd60e51b815260206004820152601260248201527114db985c1cda1bdd081b9bdd08199bdd5b9960721b604482015260640161092c565b836101cc8281548110611dd057611dd061301c565b6000918252602082200191909155604051859187917fe2ad3b1abe53383dbe6359f02f11ae76d91cfab321b37083b16e1d96a81d41839190a35050505050565b6101635460405163d4ce141560e01b81526001600160a01b038581166004830152848116602483015260448201849052600092169063d4ce141590606401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108699190613146565b804210611ed65760405162461bcd60e51b8152602060048201526015602482015274536e617073686f7420616c726561647920646f6e6560581b604482015260640161092c565b600080611ee2836122df565b9150915081611f285760405162461bcd60e51b815260206004820152601260248201527114db985c1cda1bdd081b9bdd08199bdd5b9960721b604482015260640161092c565b611f3181612524565b60405183907f06e2498f5548e5491bfe985562cc494131eae56b5b6543b59129c8886f129f6590600090a2505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303611fa0575060131936013560601c90565b503390565b600080611fb06111f0565b9050611fbd85828561259b565b610aa5858585611a57565b611fd28282610dc9565b61093f57611fea816001600160a01b0316601461260f565b611ff583602061260f565b604051602001612006929190613163565b60408051601f198184030181529082905262461bcd60e51b825261092c91600401612ad3565b60fe5460ff166120755760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092c565b565b60fe5460ff16156120d55760405162461bcd60e51b815260206004820152602260248201527f434d5441543a20746f6b656e207472616e73666572207768696c652070617573604482015261195960f21b606482015260840161092c565b6001600160a01b0383166000908152610130602052604090205460ff161561214a5760405162461bcd60e51b815260206004820152602260248201527f434d5441543a20746f6b656e207472616e73666572207768696c652066726f7a60448201526132b760f11b606482015260840161092c565b6121558383836127ab565b610163546001600160a01b031615610898576121728383836127f4565b6108985760405162461bcd60e51b815260206004820152602d60248201527f434d5441543a207472616e736665722072656a65637465642062792076616c6960448201526c646174696f6e206d6f64756c6560981b606482015260840161092c565b815460009081036121e757506000610714565b82546000905b808210156122435760006122018383612873565b9050848682815481106122165761221661301c565b9060005260206000200154111561222f5780915061223d565b61223a816001612ee7565b92505b506121ed565b6000821180156122785750838561225b600185613032565b8154811061226b5761226b61301c565b9060005260206000200154145b1561229157612288600183613032565b92505050610714565b509050610714565b60fe5460ff16156120755760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092c565b60008060005b6101cc5481101561233257836101cc82815481106123055761230561301c565b90600052602060002001540361232057600194909350915050565b8061232a816131d8565b9150506122e5565b50600093849350915050565b600054610100900460ff166120755760405162461bcd60e51b815260040161092c906130fb565b600054610100900460ff1661238c5760405162461bcd60e51b815260040161092c906130fb565b6065805460ff191660ff851617905560666123a78382612f40565b506067611c2c8282612f40565b600054610100900460ff166123db5760405162461bcd60e51b815260040161092c906130fb565b60366123e78382612f40565b5060376108988282612f40565b600054610100900460ff1661241b5760405162461bcd60e51b815260040161092c906130fb565b60fe805460ff19169055565b600054610100900460ff1661244e5760405162461bcd60e51b815260040161092c906130fb565b60006101cb55565b600054610100900460ff1661247d5760405162461bcd60e51b815260040161092c906130fb565b61248860008261288e565b6124a06000805160206132ba8339815191528261288e565b6124ca7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68261288e565b6124f47f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8488261288e565b61250c60008051602061327a8339815191528261288e565b61098f60008051602061329a8339815191528261288e565b6101cc805461253590600190613032565b815481106125455761254561301c565b90600052602060002001546101cc82815481106125645761256461301c565b6000918252602090912001556101cc805480612582576125826131f1565b6001900381819060005260206000200160009055905550565b60006125a7848461114c565b90506000198114611c2c57818110156126025760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161092c565b611c2c84848484036111fa565b6060600061261e836002613207565b612629906002612ee7565b67ffffffffffffffff81111561264157612641612c23565b6040519080825280601f01601f19166020018201604052801561266b576020820181803683370190505b509050600360fc1b816000815181106126865761268661301c565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106126b5576126b561301c565b60200101906001600160f81b031916908160001a90535060006126d9846002613207565b6126e4906001612ee7565b90505b600181111561275c576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106127185761271861301c565b1a60f81b82828151811061272e5761272e61301c565b60200101906001600160f81b031916908160001a90535060049490941c936127558161321e565b90506126e7565b50831561086c5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161092c565b6127b3612898565b6001600160a01b038316156127eb576127cb836128b8565b6001600160a01b038216156127e357610898826128b8565b6108986128ec565b6127e3826128b8565b6101635460405163634a350960e11b81526001600160a01b038581166004830152848116602483015260448201849052600092169063c6946a1290606401602060405180830381865afa15801561284f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108699190613235565b60006128826002848418613257565b61086c90848416612ee7565b61093f82826113a5565b60006128a26128fb565b9050801561098f576101cb81905561098f6129a1565b6001600160a01b03811660009081526101c86020908152604080832060339092529091205461098f91906129f4565b6129f4565b6120756101c96128e760355490565b6101cc54600090810361290e5750600090565b6000805b6101cc54811015610ad657426101cc82815481106129325761293261301c565b9060005260206000200154111580156129685750816101cc828154811061295b5761295b61301c565b9060005260206000200154115b1561298f576101cc81815481106129815761298161301c565b906000526020600020015491505b80612999816131d8565b915050612912565b60005b6101cc5481101561098f57426101cc82815481106129c4576129c461301c565b9060005260206000200154116129e2576129dd81612524565b6129a4565b6129ed600182612ee7565b90506129a4565b6000612a006101cb5490565b905080612a0c84612a40565b1015610898578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b80546000908103612a5357506000919050565b81548290612a6390600190613032565b81548110612a7357612a7361301c565b90600052602060002001549050919050565b600060208284031215612a9757600080fd5b81356001600160e01b03198116811461086c57600080fd5b60005b83811015612aca578181015183820152602001612ab2565b50506000910152565b6020815260008251806020840152612af2816040850160208701612aaf565b601f01601f19169190910160400192915050565b6001600160a01b038116811461098f57600080fd5b60008060408385031215612b2e57600080fd5b8235612b3981612b06565b946020939093013593505050565b600080600060608486031215612b5c57600080fd5b8335612b6781612b06565b92506020840135612b7781612b06565b929592945050506040919091013590565b600060208284031215612b9a57600080fd5b5035919050565b60008060408385031215612bb457600080fd5b823591506020830135612bc681612b06565b809150509250929050565b600080600060608486031215612be657600080fd5b8335612bf181612b06565b95602085013595506040909401359392505050565b600060208284031215612c1857600080fd5b813561086c81612b06565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612c6257612c62612c23565b604052919050565b600067ffffffffffffffff821115612c8457612c84612c23565b50601f01601f191660200190565b600082601f830112612ca357600080fd5b8135612cb6612cb182612c6a565b612c39565b818152846020838601011115612ccb57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215612cfa57600080fd5b813567ffffffffffffffff811115612d1157600080fd5b610b0084828501612c92565b60ff8116811461098f57600080fd5b600060208284031215612d3e57600080fd5b813561086c81612d1d565b600080600080600060a08688031215612d6157600080fd5b8535612d6c81612b06565b9450602086013567ffffffffffffffff80821115612d8957600080fd5b612d9589838a01612c92565b95506040880135915080821115612dab57600080fd5b612db789838a01612c92565b94506060880135915080821115612dcd57600080fd5b612dd989838a01612c92565b93506080880135915080821115612def57600080fd5b50612dfc88828901612c92565b9150509295509295909350565b60008060408385031215612e1c57600080fd5b50508035926020909101359150565b60008060408385031215612e3e57600080fd5b8235612e4981612b06565b91506020830135612bc681612b06565b6020808252825182820181905260009190848201906040850190845b81811015612e9157835183529284019291840191600101612e75565b50909695505050505050565b600181811c90821680612eb157607f821691505b602082108103610ad657634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561071457610714612ed1565b601f82111561089857600081815260208120601f850160051c81016020861015612f215750805b601f850160051c820191505b8181101561102c57828155600101612f2d565b815167ffffffffffffffff811115612f5a57612f5a612c23565b612f6e81612f688454612e9d565b84612efa565b602080601f831160018114612fa35760008415612f8b5750858301515b600019600386901b1c1916600185901b17855561102c565b600085815260208120601f198616915b82811015612fd257888601518255948401946001909101908401612fb3565b5085821015612ff05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251613012818460208701612aaf565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561071457610714612ed1565b60006020828403121561305757600080fd5b815167ffffffffffffffff81111561306e57600080fd5b8201601f8101841361307f57600080fd5b805161308d612cb182612c6a565b8181528560208385010111156130a257600080fd5b610b59826020830160208601612aaf565b60208082526028908201527f536e617073686f7420616c7265616479207363686564756c656420666f7220746040820152676869732074696d6560c01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561315857600080fd5b815161086c81612d1d565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161319b816017850160208801612aaf565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516131cc816028840160208801612aaf565b01602801949350505050565b6000600182016131ea576131ea612ed1565b5060010190565b634e487b7160e01b600052603160045260246000fd5b808202811582820484141761071457610714612ed1565b60008161322d5761322d612ed1565b506000190190565b60006020828403121561324757600080fd5b8151801515811461086c57600080fd5b60008261327457634e487b7160e01b600052601260045260246000fd5b50049056fe65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a809a0fc49fc0600540f1d39e23454e1f6f215bc7505fa22b17c154616570ddef973ef39d76cc2c6090feab1c030bec6ab5db557f64df047a4c4f9b5953cf1df3a2646970667358221220a909904b22cdfda408a2defda054c455be54767f3c6f55aab9e1cc5736ee004464736f6c634300081100330000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102bb5760003560e01c806378f86afc11610182578063b6dbcae5116100e9578063d547741f116100a2578063e20c35e51161007c578063e20c35e51461067a578063e63ab1e91461068d578063fb78ed40146106a2578063fcf196b4146106b757600080fd5b8063d547741f14610641578063dcfd616f14610654578063dd62ed3e1461066757600080fd5b8063b6dbcae5146105ac578063d0516650146105bf578063d21268ef146105ec578063d4ce1415146105ff578063d502562514610612578063d53913931461061a57600080fd5b806395d89b411161013b57806395d89b4114610550578063a217fddf14610558578063a312e15514610560578063a457c2d714610573578063a4a0a30114610586578063a9059cbb1461059957600080fd5b806378f86afc146104e957806379cc6790146104fc5780637f4ab1dd1461050f5780638456cb59146105225780638d1fdf2f1461052a57806391d148541461053d57600080fd5b80633950935111610226578063572b6c05116101df578063572b6c051461043a5780635c975abb1461047a5780635ee7a94214610485578063634daf76146104985780636439fd75146104ab57806370a08231146104c057600080fd5b806339509351146103de5780633f4ba83a146103f157806340c10f19146103f957806341c0e1b51461040c578063426a84931461041457806345c8b1a61461042757600080fd5b8063246b72ec11610278578063246b72ec1461033d578063248a9ca314610352578063282c51f3146103755780632f2ff15d1461039c578063313ce567146103b157806336568abe146103cb57600080fd5b806301ffc9a7146102c057806306fdde03146102e8578063095ea7b3146102fd57806317d70f7c1461031057806318160ddd1461031857806323b872dd1461032a575b600080fd5b6102d36102ce366004612a85565b6106e3565b60405190151581526020015b60405180910390f35b6102f061071a565b6040516102df9190612ad3565b6102d361030b366004612b1b565b6107ac565b6102f06107ce565b6035545b6040519081526020016102df565b6102d3610338366004612b47565b61085c565b61031c60008051602061329a83398151915281565b61031c610360366004612b88565b600090815260cc602052604090206001015490565b61031c7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b6103af6103aa366004612ba1565b610873565b005b6103b961089d565b60405160ff90911681526020016102df565b6103af6103d9366004612ba1565b6108b0565b6102d36103ec366004612b1b565b610943565b6103af61096f565b6103af610407366004612b1b565b610992565b6103af610a0e565b6102d3610422366004612bd1565b610a2c565b6102d3610435366004612c06565b610ab0565b6102d3610448366004612c06565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b60fe5460ff166102d3565b61031c610493366004612b88565b610adc565b61031c6104a6366004612ba1565b610b08565b61031c6000805160206132ba83398151915281565b61031c6104ce366004612c06565b6001600160a01b031660009081526033602052604090205490565b6103af6104f7366004612ce8565b610b62565b6103af61050a366004612b1b565b610bbc565b6102f061051d366004612d2c565b610cb9565b6103af610d86565b6102d3610538366004612c06565b610da6565b6102d361054b366004612ba1565b610dc9565b6102f0610df4565b61031c600081565b6103af61056e366004612b88565b610e03565b6102d3610581366004612b1b565b610e24565b6103af610594366004612c06565b610eaa565b6102d36105a7366004612b1b565b610f01565b6103af6105ba366004612d49565b610f19565b6102d36105cd366004612c06565b6001600160a01b03166000908152610130602052604090205460ff1690565b6103af6105fa366004612e09565b611034565b6103b961060d366004612b47565b611056565b6102f06110c0565b61031c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b6103af61064f366004612ba1565b6110cd565b6103af610662366004612ce8565b6110f2565b61031c610675366004612e2b565b61114c565b6103af610688366004612b88565b611177565b61031c60008051602061327a83398151915281565b6106aa611198565b6040516102df9190612e59565b610163546106cb906001600160a01b031681565b6040516001600160a01b0390911681526020016102df565b60006001600160e01b03198216637965db0b60e01b148061071457506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606036805461072990612e9d565b80601f016020809104026020016040519081016040528092919081815260200182805461075590612e9d565b80156107a25780601f10610777576101008083540402835291602001916107a2565b820191906000526020600020905b81548152906001019060200180831161078557829003601f168201915b5050505050905090565b6000806107b76111f0565b90506107c48185856111fa565b5060019392505050565b606680546107db90612e9d565b80601f016020809104026020016040519081016040528092919081815260200182805461080790612e9d565b80156108545780601f1061082957610100808354040283529160200191610854565b820191906000526020600020905b81548152906001019060200180831161083757829003601f168201915b505050505081565b600061086984848461131e565b90505b9392505050565b600082815260cc602052604090206001015461088e81611394565b61089883836113a5565b505050565b60006108ab60655460ff1690565b905090565b6108b86111f0565b6001600160a01b0316816001600160a01b0316146109355760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b61093f828261142c565b5050565b60008061094e6111f0565b90506107c4818585610960858961114c565b61096a9190612ee7565b6111fa565b60008051602061327a83398151915261098781611394565b61098f6114b1565b50565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a66109bc81611394565b6109c68383611509565b826001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688583604051610a0191815260200190565b60405180910390a2505050565b6000610a1981611394565b610a216111f0565b6001600160a01b0316ff5b600081610a40610a3a6111f0565b8661114c565b14610a9b5760405162461bcd60e51b815260206004820152602560248201527f434d5441543a2063757272656e7420616c6c6f77616e6365206973206e6f74206044820152641c9a59da1d60da1b606482015260840161092c565b610aa584846107ac565b506001949350505050565b60006000805160206132ba833981519152610aca81611394565b610ad3836115f4565b91505b50919050565b6000806000610aed846101c9611683565b9150915081610afe57603554610b00565b805b949350505050565b6001600160a01b03811660009081526101c86020526040812081908190610b30908690611683565b9150915081610b57576001600160a01b038416600090815260336020526040902054610b59565b805b95945050505050565b6000610b6d81611394565b6067610b798382612f40565b5081604051610b889190613000565b604051908190038120907f04ad91be0cc2638e10a8fa52bb61221dcf70dfcd07e6beae6b0d5a3f75070fcf90600090a25050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848610be681611394565b6000610bf4846106756111f0565b905082811015610c525760405162461bcd60e51b8152602060048201526024808201527f434d5441543a206275726e20616d6f756e74206578636565647320616c6c6f77604482015263616e636560e01b606482015260840161092c565b610c6684610c5e6111f0565b8584036111fa565b610c7084846116d8565b836001600160a01b03167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca584604051610cab91815260200190565b60405180910390a250505050565b606060ff8216610ced57505060408051808201909152600e81526d2737903932b9ba3934b1ba34b7b760911b602082015290565b60001960ff831601610d29575050604080518082019091526014815273105b1b081d1c985b9cd9995c9cc81c185d5cd95960621b602082015290565b60011960ff831601610d665750506040805180820190915260158152742a34329030b2323932b9b99034b990333937bd32b760591b602082015290565b610163546001600160a01b031615610d815761071482611832565b919050565b60008051602061327a833981519152610d9e81611394565b61098f6118a7565b60006000805160206132ba833981519152610dc081611394565b610ad3836118e5565b600091825260cc602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60606037805461072990612e9d565b60008051602061329a833981519152610e1b81611394565b61093f82611978565b600080610e2f6111f0565b90506000610e3d828661114c565b905083811015610e9d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161092c565b610aa582868684036111fa565b6000610eb581611394565b61016380546001600160a01b0319166001600160a01b0384169081179091556040517f9c4d5c11b88d1e3d9c7ad50900cb6d10ac72853248cdc85ca868fb772e62b44990600090a25050565b600080610f0c6111f0565b90506107c4818585611a57565b600054610100900460ff1615808015610f395750600054600160ff909116105b80610f535750303b158015610f53575060005460ff166001145b610fb65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161092c565b6000805460ff191660011790558015610fd9576000805461ff0019166101001790555b610fe68686868686611c32565b801561102c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b60008051602061329a83398151915261104c81611394565b6108988383611ca7565b600061106460fe5460ff1690565b156110735760015b905061086c565b6001600160a01b0384166000908152610130602052604090205460ff161561109c57600261106c565b610163546001600160a01b0316156110b95761106c848484611e10565b6000610869565b606780546107db90612e9d565b600082815260cc60205260409020600101546110e881611394565b610898838361142c565b60006110fd81611394565b60666111098382612f40565b50816040516111189190613000565b604051908190038120907f1a3f197f2cb06b445ad0c131c52bc822947dae771f49d55fbd17bb6e462254bd90600090a25050565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60008051602061329a83398151915261118f81611394565b61093f82611e8f565b60606101cc8054806020026020016040519081016040528092919081815260200182805480156107a257602002820191906000526020600020905b8154815260200190600101908083116111d3575050505050905090565b60006108ab611f61565b6001600160a01b03831661125c5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161092c565b6001600160a01b0382166112bd5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161092c565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60008061132c858585611fa5565b9050801515600103610869576113406111f0565b6001600160a01b0316856001600160a01b03167f7c2b9369bf4a6bd9745889c658ad00a4d57e280c4c80fa1c74db2a9e52c136358560405161138491815260200190565b60405180910390a3949350505050565b61098f816113a06111f0565b611fc8565b6113af8282610dc9565b61093f57600082815260cc602090815260408083206001600160a01b03851684529091529020805460ff191660011790556113e86111f0565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6114368282610dc9565b1561093f57600082815260cc602090815260408083206001600160a01b03851684529091529020805460ff1916905561146d6111f0565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b6114b961202c565b60fe805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6114ec6111f0565b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03821661155f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161092c565b61156b60008383612077565b806035600082825461157d9190612ee7565b90915550506001600160a01b038216600090815260336020526040812080548392906115aa908490612ee7565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b0381166000908152610130602052604081205460ff1661161d57506000919050565b6001600160a01b038216600081815261013060205260409020805460ff191690556116466111f0565b6001600160a01b03167f4f3ab9ff0cc4f039268532098e01239544b0420171876e36889d01c62c784c7960405160405180910390a3506001919050565b6000808061169184866121d4565b845490915081036116a95760008092509250506116d1565b60018460010182815481106116c0576116c061301c565b906000526020600020015492509250505b9250929050565b6001600160a01b0382166117385760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161092c565b61174482600083612077565b6001600160a01b038216600090815260336020526040902054818110156117b85760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161092c565b6001600160a01b03831660009081526033602052604081208383039055603580548492906117e7908490613032565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b61016354604051637f4ab1dd60e01b815260ff831660048201526060916001600160a01b031690637f4ab1dd90602401600060405180830381865afa15801561187f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107149190810190613045565b6118af612299565b60fe805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114ec6111f0565b6001600160a01b0381166000908152610130602052604081205460ff161561190f57506000919050565b6001600160a01b038216600081815261013060205260409020805460ff1916600117905561193b6111f0565b6001600160a01b03167f51d18786e9cb144f87d46e7b796309ea84c7c687d91e09c97f051eacf59bc52860405160405180910390a3506001919050565b8042106119c75760405162461bcd60e51b815260206004820152601e60248201527f536e617073686f74207363686564756c656420696e2074686520706173740000604482015260640161092c565b60006119d2826122df565b50905080156119f35760405162461bcd60e51b815260040161092c906130b3565b6101cc805460018101825560009182527f9a37fbd5e796e9046c2f5f7e29046a230a4ba9ada48a80535ed93a51fec5cfbc018390556040518391907fe2ad3b1abe53383dbe6359f02f11ae76d91cfab321b37083b16e1d96a81d4183908290a35050565b6001600160a01b038316611abb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161092c565b6001600160a01b038216611b1d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161092c565b611b28838383612077565b6001600160a01b03831660009081526033602052604090205481811015611ba05760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161092c565b6001600160a01b03808516600090815260336020526040808220858503905591851681529081208054849290611bd7908490612ee7565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611c2391815260200190565b60405180910390a35b50505050565b600054610100900460ff16611c595760405162461bcd60e51b815260040161092c906130fb565b611c6161233e565b611c6d60008383612365565b611c7561233e565b611c7f84846123b4565b611c876123f4565b611c8f61233e565b611c97612427565b611ca085612456565b5050505050565b814210611cee5760405162461bcd60e51b8152602060048201526015602482015274536e617073686f7420616c726561647920646f6e6560581b604482015260640161092c565b804210611d3d5760405162461bcd60e51b815260206004820152601e60248201527f536e617073686f74207363686564756c656420696e2074686520706173740000604482015260640161092c565b6000611d48826122df565b5090508015611d695760405162461bcd60e51b815260040161092c906130b3565b600080611d75856122df565b9150915081611dbb5760405162461bcd60e51b815260206004820152601260248201527114db985c1cda1bdd081b9bdd08199bdd5b9960721b604482015260640161092c565b836101cc8281548110611dd057611dd061301c565b6000918252602082200191909155604051859187917fe2ad3b1abe53383dbe6359f02f11ae76d91cfab321b37083b16e1d96a81d41839190a35050505050565b6101635460405163d4ce141560e01b81526001600160a01b038581166004830152848116602483015260448201849052600092169063d4ce141590606401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108699190613146565b804210611ed65760405162461bcd60e51b8152602060048201526015602482015274536e617073686f7420616c726561647920646f6e6560581b604482015260640161092c565b600080611ee2836122df565b9150915081611f285760405162461bcd60e51b815260206004820152601260248201527114db985c1cda1bdd081b9bdd08199bdd5b9960721b604482015260640161092c565b611f3181612524565b60405183907f06e2498f5548e5491bfe985562cc494131eae56b5b6543b59129c8886f129f6590600090a2505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303611fa0575060131936013560601c90565b503390565b600080611fb06111f0565b9050611fbd85828561259b565b610aa5858585611a57565b611fd28282610dc9565b61093f57611fea816001600160a01b0316601461260f565b611ff583602061260f565b604051602001612006929190613163565b60408051601f198184030181529082905262461bcd60e51b825261092c91600401612ad3565b60fe5460ff166120755760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092c565b565b60fe5460ff16156120d55760405162461bcd60e51b815260206004820152602260248201527f434d5441543a20746f6b656e207472616e73666572207768696c652070617573604482015261195960f21b606482015260840161092c565b6001600160a01b0383166000908152610130602052604090205460ff161561214a5760405162461bcd60e51b815260206004820152602260248201527f434d5441543a20746f6b656e207472616e73666572207768696c652066726f7a60448201526132b760f11b606482015260840161092c565b6121558383836127ab565b610163546001600160a01b031615610898576121728383836127f4565b6108985760405162461bcd60e51b815260206004820152602d60248201527f434d5441543a207472616e736665722072656a65637465642062792076616c6960448201526c646174696f6e206d6f64756c6560981b606482015260840161092c565b815460009081036121e757506000610714565b82546000905b808210156122435760006122018383612873565b9050848682815481106122165761221661301c565b9060005260206000200154111561222f5780915061223d565b61223a816001612ee7565b92505b506121ed565b6000821180156122785750838561225b600185613032565b8154811061226b5761226b61301c565b9060005260206000200154145b1561229157612288600183613032565b92505050610714565b509050610714565b60fe5460ff16156120755760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092c565b60008060005b6101cc5481101561233257836101cc82815481106123055761230561301c565b90600052602060002001540361232057600194909350915050565b8061232a816131d8565b9150506122e5565b50600093849350915050565b600054610100900460ff166120755760405162461bcd60e51b815260040161092c906130fb565b600054610100900460ff1661238c5760405162461bcd60e51b815260040161092c906130fb565b6065805460ff191660ff851617905560666123a78382612f40565b506067611c2c8282612f40565b600054610100900460ff166123db5760405162461bcd60e51b815260040161092c906130fb565b60366123e78382612f40565b5060376108988282612f40565b600054610100900460ff1661241b5760405162461bcd60e51b815260040161092c906130fb565b60fe805460ff19169055565b600054610100900460ff1661244e5760405162461bcd60e51b815260040161092c906130fb565b60006101cb55565b600054610100900460ff1661247d5760405162461bcd60e51b815260040161092c906130fb565b61248860008261288e565b6124a06000805160206132ba8339815191528261288e565b6124ca7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68261288e565b6124f47f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8488261288e565b61250c60008051602061327a8339815191528261288e565b61098f60008051602061329a8339815191528261288e565b6101cc805461253590600190613032565b815481106125455761254561301c565b90600052602060002001546101cc82815481106125645761256461301c565b6000918252602090912001556101cc805480612582576125826131f1565b6001900381819060005260206000200160009055905550565b60006125a7848461114c565b90506000198114611c2c57818110156126025760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161092c565b611c2c84848484036111fa565b6060600061261e836002613207565b612629906002612ee7565b67ffffffffffffffff81111561264157612641612c23565b6040519080825280601f01601f19166020018201604052801561266b576020820181803683370190505b509050600360fc1b816000815181106126865761268661301c565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106126b5576126b561301c565b60200101906001600160f81b031916908160001a90535060006126d9846002613207565b6126e4906001612ee7565b90505b600181111561275c576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106127185761271861301c565b1a60f81b82828151811061272e5761272e61301c565b60200101906001600160f81b031916908160001a90535060049490941c936127558161321e565b90506126e7565b50831561086c5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161092c565b6127b3612898565b6001600160a01b038316156127eb576127cb836128b8565b6001600160a01b038216156127e357610898826128b8565b6108986128ec565b6127e3826128b8565b6101635460405163634a350960e11b81526001600160a01b038581166004830152848116602483015260448201849052600092169063c6946a1290606401602060405180830381865afa15801561284f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108699190613235565b60006128826002848418613257565b61086c90848416612ee7565b61093f82826113a5565b60006128a26128fb565b9050801561098f576101cb81905561098f6129a1565b6001600160a01b03811660009081526101c86020908152604080832060339092529091205461098f91906129f4565b6129f4565b6120756101c96128e760355490565b6101cc54600090810361290e5750600090565b6000805b6101cc54811015610ad657426101cc82815481106129325761293261301c565b9060005260206000200154111580156129685750816101cc828154811061295b5761295b61301c565b9060005260206000200154115b1561298f576101cc81815481106129815761298161301c565b906000526020600020015491505b80612999816131d8565b915050612912565b60005b6101cc5481101561098f57426101cc82815481106129c4576129c461301c565b9060005260206000200154116129e2576129dd81612524565b6129a4565b6129ed600182612ee7565b90506129a4565b6000612a006101cb5490565b905080612a0c84612a40565b1015610898578254600180820185556000858152602080822090930193909355938401805494850181558252902090910155565b80546000908103612a5357506000919050565b81548290612a6390600190613032565b81548110612a7357612a7361301c565b90600052602060002001549050919050565b600060208284031215612a9757600080fd5b81356001600160e01b03198116811461086c57600080fd5b60005b83811015612aca578181015183820152602001612ab2565b50506000910152565b6020815260008251806020840152612af2816040850160208701612aaf565b601f01601f19169190910160400192915050565b6001600160a01b038116811461098f57600080fd5b60008060408385031215612b2e57600080fd5b8235612b3981612b06565b946020939093013593505050565b600080600060608486031215612b5c57600080fd5b8335612b6781612b06565b92506020840135612b7781612b06565b929592945050506040919091013590565b600060208284031215612b9a57600080fd5b5035919050565b60008060408385031215612bb457600080fd5b823591506020830135612bc681612b06565b809150509250929050565b600080600060608486031215612be657600080fd5b8335612bf181612b06565b95602085013595506040909401359392505050565b600060208284031215612c1857600080fd5b813561086c81612b06565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612c6257612c62612c23565b604052919050565b600067ffffffffffffffff821115612c8457612c84612c23565b50601f01601f191660200190565b600082601f830112612ca357600080fd5b8135612cb6612cb182612c6a565b612c39565b818152846020838601011115612ccb57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215612cfa57600080fd5b813567ffffffffffffffff811115612d1157600080fd5b610b0084828501612c92565b60ff8116811461098f57600080fd5b600060208284031215612d3e57600080fd5b813561086c81612d1d565b600080600080600060a08688031215612d6157600080fd5b8535612d6c81612b06565b9450602086013567ffffffffffffffff80821115612d8957600080fd5b612d9589838a01612c92565b95506040880135915080821115612dab57600080fd5b612db789838a01612c92565b94506060880135915080821115612dcd57600080fd5b612dd989838a01612c92565b93506080880135915080821115612def57600080fd5b50612dfc88828901612c92565b9150509295509295909350565b60008060408385031215612e1c57600080fd5b50508035926020909101359150565b60008060408385031215612e3e57600080fd5b8235612e4981612b06565b91506020830135612bc681612b06565b6020808252825182820181905260009190848201906040850190845b81811015612e9157835183529284019291840191600101612e75565b50909695505050505050565b600181811c90821680612eb157607f821691505b602082108103610ad657634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561071457610714612ed1565b601f82111561089857600081815260208120601f850160051c81016020861015612f215750805b601f850160051c820191505b8181101561102c57828155600101612f2d565b815167ffffffffffffffff811115612f5a57612f5a612c23565b612f6e81612f688454612e9d565b84612efa565b602080601f831160018114612fa35760008415612f8b5750858301515b600019600386901b1c1916600185901b17855561102c565b600085815260208120601f198616915b82811015612fd257888601518255948401946001909101908401612fb3565b5085821015612ff05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251613012818460208701612aaf565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b8181038181111561071457610714612ed1565b60006020828403121561305757600080fd5b815167ffffffffffffffff81111561306e57600080fd5b8201601f8101841361307f57600080fd5b805161308d612cb182612c6a565b8181528560208385010111156130a257600080fd5b610b59826020830160208601612aaf565b60208082526028908201527f536e617073686f7420616c7265616479207363686564756c656420666f7220746040820152676869732074696d6560c01b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561315857600080fd5b815161086c81612d1d565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161319b816017850160208801612aaf565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516131cc816028840160208801612aaf565b01602801949350505050565b6000600182016131ea576131ea612ed1565b5060010190565b634e487b7160e01b600052603160045260246000fd5b808202811582820484141761071457610714612ed1565b60008161322d5761322d612ed1565b506000190190565b60006020828403121561324757600080fd5b8151801515811461086c57600080fd5b60008261327457634e487b7160e01b600052601260045260246000fd5b50049056fe65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a809a0fc49fc0600540f1d39e23454e1f6f215bc7505fa22b17c154616570ddef973ef39d76cc2c6090feab1c030bec6ab5db557f64df047a4c4f9b5953cf1df3a2646970667358221220a909904b22cdfda408a2defda054c455be54767f3c6f55aab9e1cc5736ee004464736f6c63430008110033

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

0000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : forwarder (address): 0x0000000000000000000000000000000000000000

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

83838:8786:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46384:215;;;;;;:::i;:::-;;:::i;:::-;;;470:14:1;;463:22;445:41;;433:2;418:18;46384:215:0;;;;;;;;21016:100;;;:::i;:::-;;;;;;;:::i;23367:201::-;;;;;;:::i;:::-;;:::i;32434:21::-;;;:::i;22136:108::-;22224:12;;22136:108;;;1755:25:1;;;1743:2;1728:18;22136:108:0;1609:177:1;88189:247:0;;;;;;:::i;:::-;;:::i;76092:72::-;;-1:-1:-1;;;;;;;;;;;76092:72:0;;48253:131;;;;;;:::i;:::-;48327:7;48354:12;;;:6;:12;;;;;:22;;;;48253:131;52685:62;;52723:24;52685:62;;48694:147;;;;;;:::i;:::-;;:::i;:::-;;87994:187;;;:::i;:::-;;;3111:4:1;3099:17;;;3081:36;;3069:2;3054:18;87994:187:0;2939:184:1;49838:218:0;;;;;;:::i;:::-;;:::i;24852:238::-;;;;;;:::i;:::-;;:::i;87463:77::-;;;:::i;86021:139::-;;;;;;:::i;:::-;;:::i;91265:106::-;;;:::i;35025:361::-;;;;;;:::i;:::-;;:::i;87829:157::-;;;;;;:::i;:::-;;:::i;62911:138::-;;;;;;:::i;:::-;63024:17;-1:-1:-1;;;;;63011:30:0;;;;;;;62911:138;56888:86;56959:7;;;;56888:86;;78390:257;;;;;;:::i;:::-;;:::i;78067:315::-;;;;;;:::i;:::-;;:::i;53693:66::-;;-1:-1:-1;;;;;;;;;;;53693:66:0;;22307:127;;;;;;:::i;:::-;-1:-1:-1;;;;;22408:18:0;22381:7;22408:18;;;:9;:18;;;;;;;22307:127;91039:163;;;;;;:::i;:::-;;:::i;86479:479::-;;;;;;:::i;:::-;;:::i;89697:669::-;;;;;;:::i;:::-;;:::i;87172:73::-;;;:::i;87607:153::-;;;;;;:::i;:::-;;:::i;46691:147::-;;;;;;:::i;:::-;;:::i;21235:104::-;;;:::i;45785:49::-;;45830:4;45785:49;;90374:139;;;;;;:::i;:::-;;:::i;25593:436::-;;;;;;:::i;:::-;;:::i;91379:203::-;;;;;;:::i;:::-;;:::i;22640:193::-;;;;;;:::i;:::-;;:::i;84477:260::-;;;;;;:::i;:::-;;:::i;54257:110::-;;;;;;:::i;:::-;-1:-1:-1;;;;;54343:16:0;54319:4;54343:16;;;:7;:16;;;;;;;;;54257:110;90521:175;;;;;;:::i;:::-;;:::i;88799:531::-;;;;;;:::i;:::-;;:::i;32462:19::-;;;:::i;52926:62::-;;52964:24;52926:62;;49134:149;;;;;;:::i;:::-;;:::i;90855:176::-;;;;;;:::i;:::-;;:::i;22896:151::-;;;;;;:::i;:::-;;:::i;90704:143::-;;;;;;:::i;:::-;;:::i;58600:62::-;;-1:-1:-1;;;;;;;;;;;58600:62:0;;77947:112;;;:::i;:::-;;;;;;;:::i;61014:29::-;;;;;-1:-1:-1;;;;;61014:29:0;;;;;;-1:-1:-1;;;;;8864:32:1;;;8846:51;;8834:2;8819:18;61014:29:0;8680:223:1;46384:215:0;46469:4;-1:-1:-1;;;;;;46493:58:0;;-1:-1:-1;;;46493:58:0;;:98;;-1:-1:-1;;;;;;;;;;43196:51:0;;;46555:36;46486:105;46384:215;-1:-1:-1;;46384:215:0:o;21016:100::-;21070:13;21103:5;21096:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21016:100;:::o;23367:201::-;23450:4;23467:13;23483:12;:10;:12::i;:::-;23467:28;;23506:32;23515:5;23522:7;23531:6;23506:8;:32::i;:::-;-1:-1:-1;23556:4:0;;23367:201;-1:-1:-1;;;23367:201:0:o;32434:21::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;88189:247::-;88359:4;88383:45;88402:6;88410:9;88421:6;88383:18;:45::i;:::-;88376:52;;88189:247;;;;;;:::o;48694:147::-;48327:7;48354:12;;;:6;:12;;;;;:22;;;46276:16;46287:4;46276:10;:16::i;:::-;48808:25:::1;48819:4;48825:7;48808:10;:25::i;:::-;48694:147:::0;;;:::o;87994:187::-;88127:5;88157:16;34032:9;;;;;33949:100;88157:16;88150:23;;87994:187;:::o;49838:218::-;49945:12;:10;:12::i;:::-;-1:-1:-1;;;;;49934:23:0;:7;-1:-1:-1;;;;;49934:23:0;;49926:83;;;;-1:-1:-1;;;49926:83:0;;9495:2:1;49926:83:0;;;9477:21:1;9534:2;9514:18;;;9507:30;9573:34;9553:18;;;9546:62;-1:-1:-1;;;9624:18:1;;;9617:45;9679:19;;49926:83:0;;;;;;;;;50022:26;50034:4;50040:7;50022:11;:26::i;:::-;49838:218;;:::o;24852:238::-;24940:4;24957:13;24973:12;:10;:12::i;:::-;24957:28;;24996:64;25005:5;25012:7;25049:10;25021:25;25031:5;25038:7;25021:9;:25::i;:::-;:38;;;;:::i;:::-;24996:8;:64::i;87463:77::-;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;87522:10:::1;:8;:10::i;:::-;87463:77:::0;:::o;86021:139::-;52964:24;46276:16;46287:4;46276:10;:16::i;:::-;86103:17:::1;86109:2;86113:6;86103:5;:17::i;:::-;86141:2;-1:-1:-1::0;;;;;86136:16:0::1;;86145:6;86136:16;;;;1755:25:1::0;;1743:2;1728:18;;1609:177;86136:16:0::1;;;;;;;;86021:139:::0;;;:::o;91265:106::-;45830:4;46276:16;45830:4;46276:10;:16::i;:::-;91349:12:::1;:10;:12::i;:::-;-1:-1:-1::0;;;;;91328:35:0::1;;35025:361:::0;35159:4;35234:16;35198:32;35208:12;:10;:12::i;:::-;35222:7;35198:9;:32::i;:::-;:52;35176:139;;;;-1:-1:-1;;;35176:139:0;;10173:2:1;35176:139:0;;;10155:21:1;10212:2;10192:18;;;10185:30;10251:34;10231:18;;;10224:62;-1:-1:-1;;;10302:18:1;;;10295:35;10347:19;;35176:139:0;9971:401:1;35176:139:0;35326:30;35340:7;35349:6;35326:13;:30::i;:::-;-1:-1:-1;35374:4:0;;35025:361;-1:-1:-1;;;;35025:361:0:o;87829:157::-;87931:4;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;87960:18:::1;87970:7;87960:9;:18::i;:::-;87953:25;;46303:1;87829:157:::0;;;;:::o;78390:257::-;78454:7;78475:16;78493:13;78510:74;78533:4;78552:21;78510:8;:74::i;:::-;78474:110;;;;78604:11;:35;;22224:12;;78604:35;;;78618:5;78604:35;78597:42;78390:257;-1:-1:-1;;;;78390:257:0:o;78067:315::-;-1:-1:-1;;;;;78274:31:0;;78171:7;78274:31;;;:24;:31;;;;;78171:7;;;;78232:84;;78255:4;;78232:8;:84::i;:::-;78196:120;;;;78336:11;:38;;-1:-1:-1;;;;;22408:18:0;;22381:7;22408:18;;;:9;:18;;;;;;78336:38;;;78350:5;78336:38;78329:45;78067:315;-1:-1:-1;;;;;78067:315:0:o;91039:163::-;45830:4;46276:16;45830:4;46276:10;:16::i;:::-;91149:5:::1;:14;91157:6:::0;91149:5;:14:::1;:::i;:::-;;91187:6;91179:15;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;91039:163:::0;;:::o;86479:479::-;52723:24;46276:16;46287:4;46276:10;:16::i;:::-;86593:24:::1;86620:32;86630:7;86639:12;:10;:12::i;86620:32::-;86593:59;;86705:6;86685:16;:26;;86663:112;;;::::0;-1:-1:-1;;;86663:112:0;;13077:2:1;86663:112:0::1;::::0;::::1;13059:21:1::0;13116:2;13096:18;;;13089:30;13155:34;13135:18;;;13128:62;-1:-1:-1;;;13206:18:1;;;13199:34;13250:19;;86663:112:0::1;12875:400:1::0;86663:112:0::1;86811:58;86820:7;86829:12;:10;:12::i;:::-;86862:6;86843:16;:25;86811:8;:58::i;:::-;86891:22;86897:7;86906:6;86891:5;:22::i;:::-;86934:7;-1:-1:-1::0;;;;;86929:21:0::1;;86943:6;86929:21;;;;1755:25:1::0;;1743:2;1728:18;;1609:177;86929:21:0::1;;;;;;;;86582:376;86479:479:::0;;;:::o;89697:669::-;89809:21;89852:51;;;89848:511;;-1:-1:-1;;89927:16:0;;;;;;;;;;;;-1:-1:-1;;;89927:16:0;;;;;89697:669::o;89848:511::-;-1:-1:-1;;89965:64:0;;;;89961:398;;-1:-1:-1;;90053:29:0;;;;;;;;;;;;-1:-1:-1;;;90053:29:0;;;;;89697:669::o;89961:398::-;-1:-1:-1;;90104:64:0;;;;90100:259;;-1:-1:-1;;90192:29:0;;;;;;;;;;;;-1:-1:-1;;;90192:29:0;;;;;89697:669::o;90100:259::-;90251:10;;-1:-1:-1;;;;;90251:10:0;90243:33;90239:120;;90300:47;90331:15;90300:30;:47::i;90239:120::-;89697:669;;;:::o;87172:73::-;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;87229:8:::1;:6;:8::i;87607:153::-:0;87707:4;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;87736::::1;87744:7;87736;:16::i;46691:147::-:0;46777:4;46801:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;46801:29:0;;;;;;;;;;;;;;;46691:147::o;21235:104::-;21291:13;21324:7;21317:14;;;;;:::i;90374:139::-;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;90482:23:::1;90500:4;90482:17;:23::i;25593:436::-:0;25686:4;25703:13;25719:12;:10;:12::i;:::-;25703:28;;25742:24;25769:25;25779:5;25786:7;25769:9;:25::i;:::-;25742:52;;25833:15;25813:16;:35;;25805:85;;;;-1:-1:-1;;;25805:85:0;;13614:2:1;25805:85:0;;;13596:21:1;13653:2;13633:18;;;13626:30;13692:34;13672:18;;;13665:62;-1:-1:-1;;;13743:18:1;;;13736:35;13788:19;;25805:85:0;13412:401:1;25805:85:0;25926:60;25935:5;25942:7;25970:15;25951:16;:34;25926:8;:60::i;91379:203::-;45830:4;46276:16;45830:4;46276:10;:16::i;:::-;91499:10:::1;:24:::0;;-1:-1:-1;;;;;;91499:24:0::1;-1:-1:-1::0;;;;;91499:24:0;::::1;::::0;;::::1;::::0;;;91539:35:::1;::::0;::::1;::::0;-1:-1:-1;;91539:35:0::1;91379:203:::0;;:::o;22640:193::-;22719:4;22736:13;22752:12;:10;:12::i;:::-;22736:28;;22775;22785:5;22792:2;22796:6;22775:9;:28::i;84477:260::-;10851:19;10874:13;;;;;;10873:14;;10921:34;;;;-1:-1:-1;10939:12:0;;10954:1;10939:12;;;;:16;10921:34;10920:108;;;-1:-1:-1;11000:4:0;1606:19;:23;;;10961:66;;-1:-1:-1;11010:12:0;;;;;:17;10961:66;10898:204;;;;-1:-1:-1;;;10898:204:0;;14020:2:1;10898:204:0;;;14002:21:1;14059:2;14039:18;;;14032:30;14098:34;14078:18;;;14071:62;-1:-1:-1;;;14149:18:1;;;14142:44;14203:19;;10898:204:0;13818:410:1;10898:204:0;11113:12;:16;;-1:-1:-1;;11113:16:0;11128:1;11113:16;;;11140:67;;;;11175:13;:20;;-1:-1:-1;;11175:20:0;;;;;11140:67;84680:49:::1;84693:5;84700:4;84706:6;84714:7;84723:5;84680:12;:49::i;:::-;11233:14:::0;11229:102;;;11280:5;11264:21;;-1:-1:-1;;11264:21:0;;;11305:14;;-1:-1:-1;3081:36:1;;11305:14:0;;3069:2:1;3054:18;11305:14:0;;;;;;;11229:102;10840:498;84477:260;;;;;:::o;90521:175::-;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;90651:37:::1;90671:7;90680;90651:19;:37::i;88799:531::-:0;88931:10;88958:8;56959:7;;;;;56888:86;88958:8;88954:319;;;88996:38;88990:45;88983:52;;;;88954:319;-1:-1:-1;;;;;54343:16:0;;54319:4;54343:16;;;:7;:16;;;;;;;;89053:220;;;89099:38;89093:45;;89053:220;89168:10;;-1:-1:-1;;;;;89168:10:0;89160:33;89156:117;;89217:44;89244:4;89250:2;89254:6;89217:26;:44::i;89156:117::-;89296:25;89290:32;;32462:19;;;;;;;:::i;49134:149::-;48327:7;48354:12;;;:6;:12;;;;;:22;;;46276:16;46287:4;46276:10;:16::i;:::-;49249:26:::1;49261:4;49267:7;49249:11;:26::i;90855:176::-:0;45830:4;46276:16;45830:4;46276:10;:16::i;:::-;90969:7:::1;:18;90979:8:::0;90969:7;:18:::1;:::i;:::-;;91014:8;91003:20;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;90855:176:::0;;:::o;22896:151::-;-1:-1:-1;;;;;23012:18:0;;;22985:7;23012:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;22896:151::o;90704:143::-;-1:-1:-1;;;;;;;;;;;46276:16:0;46287:4;46276:10;:16::i;:::-;90814:25:::1;90834:4;90814:19;:25::i;77947:112::-:0;77996:16;78032:19;78025:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77947:112;:::o;92179:202::-;92316:14;92355:18;:16;:18::i;29218:380::-;-1:-1:-1;;;;;29354:19:0;;29346:68;;;;-1:-1:-1;;;29346:68:0;;14634:2:1;29346:68:0;;;14616:21:1;14673:2;14653:18;;;14646:30;14712:34;14692:18;;;14685:62;-1:-1:-1;;;14763:18:1;;;14756:34;14807:19;;29346:68:0;14432:400:1;29346:68:0;-1:-1:-1;;;;;29433:21:0;;29425:68;;;;-1:-1:-1;;;29425:68:0;;15039:2:1;29425:68:0;;;15021:21:1;15078:2;15058:18;;;15051:30;15117:34;15097:18;;;15090:62;-1:-1:-1;;;15168:18:1;;;15161:32;15210:19;;29425:68:0;14837:398:1;29425:68:0;-1:-1:-1;;;;;29506:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;29558:32;;1755:25:1;;;29558:32:0;;1728:18:1;29558:32:0;;;;;;;29218:380;;;:::o;34531:347::-;34671:4;34688:11;34702:45;34721:6;34729:9;34740:6;34702:18;:45::i;:::-;34688:59;-1:-1:-1;34762:14:0;;;34772:4;34762:14;34758:87;;34812:12;:10;:12::i;:::-;-1:-1:-1;;;;;34798:35:0;34804:6;-1:-1:-1;;;;;34798:35:0;;34826:6;34798:35;;;;1755:25:1;;1743:2;1728:18;;1609:177;34798:35:0;;;;;;;;34864:6;34531:347;-1:-1:-1;;;;34531:347:0:o;47142:105::-;47209:30;47220:4;47226:12;:10;:12::i;:::-;47209:10;:30::i;51435:238::-;51519:22;51527:4;51533:7;51519;:22::i;:::-;51514:152;;51558:12;;;;:6;:12;;;;;;;;-1:-1:-1;;;;;51558:29:0;;;;;;;;;:36;;-1:-1:-1;;51558:36:0;51590:4;51558:36;;;51641:12;:10;:12::i;:::-;-1:-1:-1;;;;;51614:40:0;51632:7;-1:-1:-1;;;;;51614:40:0;51626:4;51614:40;;;;;;;;;;51435:238;;:::o;51853:239::-;51937:22;51945:4;51951:7;51937;:22::i;:::-;51933:152;;;52008:5;51976:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;51976:29:0;;;;;;;;;:37;;-1:-1:-1;;51976:37:0;;;52060:12;:10;:12::i;:::-;-1:-1:-1;;;;;52033:40:0;52051:7;-1:-1:-1;;;;;52033:40:0;52045:4;52033:40;;;;;;;;;;51853:239;;:::o;57743:120::-;56752:16;:14;:16::i;:::-;57802:7:::1;:15:::0;;-1:-1:-1;;57802:15:0::1;::::0;;57833:22:::1;57842:12;:10;:12::i;:::-;57833:22;::::0;-1:-1:-1;;;;;8864:32:1;;;8846:51;;8834:2;8819:18;57833:22:0::1;;;;;;;57743:120::o:0;27457:399::-;-1:-1:-1;;;;;27541:21:0;;27533:65;;;;-1:-1:-1;;;27533:65:0;;15650:2:1;27533:65:0;;;15632:21:1;15689:2;15669:18;;;15662:30;15728:33;15708:18;;;15701:61;15779:18;;27533:65:0;15448:355:1;27533:65:0;27611:49;27640:1;27644:7;27653:6;27611:20;:49::i;:::-;27689:6;27673:12;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;27706:18:0;;;;;;:9;:18;;;;;:28;;27728:6;;27706:18;:28;;27728:6;;27706:28;:::i;:::-;;;;-1:-1:-1;;27750:37:0;;1755:25:1;;;-1:-1:-1;;;;;27750:37:0;;;27767:1;;27750:37;;1743:2:1;1728:18;27750:37:0;;;;;;;49838:218;;:::o;54723:226::-;-1:-1:-1;;;;;54807:16:0;;54785:4;54807:16;;;:7;:16;;;;;;;;54802:35;;-1:-1:-1;54832:5:0;;54723:226;-1:-1:-1;54723:226:0:o;54802:35::-;-1:-1:-1;;;;;54848:16:0;;54867:5;54848:16;;;:7;:16;;;;;:24;;-1:-1:-1;;54848:24:0;;;54897:12;:10;:12::i;:::-;-1:-1:-1;;;;;54888:31:0;;;;;;;;;;;-1:-1:-1;54937:4:0;;54723:226;-1:-1:-1;54723:226:0:o;79576:1487::-;79686:4;;;80859:34;:9;80888:4;80859:28;:34::i;:::-;80919:20;;80843:50;;-1:-1:-1;80910:29:0;;80906:150;;80964:5;80971:1;80956:17;;;;;;;80906:150;81014:4;81020:9;:16;;81037:5;81020:23;;;;;;;;:::i;:::-;;;;;;;;;81006:38;;;;;79576:1487;;;;;;:::o;28189:591::-;-1:-1:-1;;;;;28273:21:0;;28265:67;;;;-1:-1:-1;;;28265:67:0;;16142:2:1;28265:67:0;;;16124:21:1;16181:2;16161:18;;;16154:30;16220:34;16200:18;;;16193:62;-1:-1:-1;;;16271:18:1;;;16264:31;16312:19;;28265:67:0;15940:397:1;28265:67:0;28345:49;28366:7;28383:1;28387:6;28345:20;:49::i;:::-;-1:-1:-1;;;;;28432:18:0;;28407:22;28432:18;;;:9;:18;;;;;;28469:24;;;;28461:71;;;;-1:-1:-1;;;28461:71:0;;16544:2:1;28461:71:0;;;16526:21:1;16583:2;16563:18;;;16556:30;16622:34;16602:18;;;16595:62;-1:-1:-1;;;16673:18:1;;;16666:32;16715:19;;28461:71:0;16342:398:1;28461:71:0;-1:-1:-1;;;;;28568:18:0;;;;;;:9;:18;;;;;28589:23;;;28568:44;;28634:12;:22;;28606:6;;28568:18;28634:22;;28606:6;;28634:22;:::i;:::-;;;;-1:-1:-1;;28674:37:0;;1755:25:1;;;28700:1:0;;-1:-1:-1;;;;;28674:37:0;;;;;1743:2:1;1728:18;28674:37:0;;;;;;;48694:147;;;:::o;61801:216::-;61952:10;;:57;;-1:-1:-1;;;61952:57:0;;3111:4:1;3099:17;;61952:57:0;;;3081:36:1;61914:13:0;;-1:-1:-1;;;;;61952:10:0;;:40;;3054:18:1;;61952:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;61952:57:0;;;;;;;;;;;;:::i;57484:118::-;56493:19;:17;:19::i;:::-;57544:7:::1;:14:::0;;-1:-1:-1;;57544:14:0::1;57554:4;57544:14;::::0;;57574:20:::1;57581:12;:10;:12::i;54434:220::-:0;-1:-1:-1;;;;;54515:16:0;;54494:4;54515:16;;;:7;:16;;;;;;;;54511:34;;;-1:-1:-1;54540:5:0;;54434:220;-1:-1:-1;54434:220:0:o;54511:34::-;-1:-1:-1;;;;;54556:16:0;;;;;;:7;:16;;;;;:23;;-1:-1:-1;;54556:23:0;54575:4;54556:23;;;54602:12;:10;:12::i;:::-;-1:-1:-1;;;;;54595:29:0;;;;;;;;;;;-1:-1:-1;54642:4:0;;54434:220;-1:-1:-1;54434:220:0:o;76628:347::-;76715:4;76697:15;:22;76689:65;;;;-1:-1:-1;;;76689:65:0;;17734:2:1;76689:65:0;;;17716:21:1;17773:2;17753:18;;;17746:30;17812:32;17792:18;;;17785:60;17862:18;;76689:65:0;17532:354:1;76689:65:0;76766:10;76782:33;76810:4;76782:27;:33::i;:::-;76765:50;;;76835:5;76834:6;76826:59;;;;-1:-1:-1;;;76826:59:0;;;;;;;:::i;:::-;76896:19;:30;;;;;;;-1:-1:-1;76896:30:0;;;;;;;;76942:25;;76921:4;;-1:-1:-1;76942:25:0;;-1:-1:-1;;76942:25:0;76678:297;76628:347;:::o;26499:671::-;-1:-1:-1;;;;;26630:18:0;;26622:68;;;;-1:-1:-1;;;26622:68:0;;18502:2:1;26622:68:0;;;18484:21:1;18541:2;18521:18;;;18514:30;18580:34;18560:18;;;18553:62;-1:-1:-1;;;18631:18:1;;;18624:35;18676:19;;26622:68:0;18300:401:1;26622:68:0;-1:-1:-1;;;;;26709:16:0;;26701:64;;;;-1:-1:-1;;;26701:64:0;;18908:2:1;26701:64:0;;;18890:21:1;18947:2;18927:18;;;18920:30;18986:34;18966:18;;;18959:62;-1:-1:-1;;;19037:18:1;;;19030:33;19080:19;;26701:64:0;18706:399:1;26701:64:0;26778:38;26799:4;26805:2;26809:6;26778:20;:38::i;:::-;-1:-1:-1;;;;;26851:15:0;;26829:19;26851:15;;;:9;:15;;;;;;26885:21;;;;26877:72;;;;-1:-1:-1;;;26877:72:0;;19312:2:1;26877:72:0;;;19294:21:1;19351:2;19331:18;;;19324:30;19390:34;19370:18;;;19363:62;-1:-1:-1;;;19441:18:1;;;19434:36;19487:19;;26877:72:0;19110:402:1;26877:72:0;-1:-1:-1;;;;;26985:15:0;;;;;;;:9;:15;;;;;;27003:20;;;26985:38;;27045:13;;;;;;;;:23;;27017:6;;26985:15;27045:23;;27017:6;;27045:23;:::i;:::-;;;;;;;;27101:2;-1:-1:-1;;;;;27086:26:0;27095:4;-1:-1:-1;;;;;27086:26:0;;27105:6;27086:26;;;;1755:25:1;;1743:2;1728:18;;1609:177;27086:26:0;;;;;;;;27125:37;26611:559;26499:671;;;:::o;84928:544::-;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;:::-;85140:26:::1;:24;:26::i;:::-;85177:40;85199:1;85202:7;85211:5;85177:21;:40::i;:::-;85228:32;:30;:32::i;:::-;85271:36;85294:4;85300:6;85271:22;:36::i;:::-;85318:27;:25;:27::i;:::-;85356:30;:28;:30::i;:::-;85397:27;:25;:27::i;:::-;85435:29;85458:5;85435:22;:29::i;:::-;84928:544:::0;;;;;:::o;76983:618::-;77106:7;77088:15;:25;77080:59;;;;-1:-1:-1;;;77080:59:0;;20131:2:1;77080:59:0;;;20113:21:1;20170:2;20150:18;;;20143:30;-1:-1:-1;;;20189:18:1;;;20182:51;20250:18;;77080:59:0;19929:345:1;77080:59:0;77176:7;77158:15;:25;77150:68;;;;-1:-1:-1;;;77150:68:0;;17734:2:1;77150:68:0;;;17716:21:1;17773:2;17753:18;;;17746:30;17812:32;17792:18;;;17785:60;17862:18;;77150:68:0;17532:354:1;77150:68:0;77232:13;77251:36;77279:7;77251:27;:36::i;:::-;77231:56;;;77307:8;77306:9;77298:62;;;;-1:-1:-1;;;77298:62:0;;;;;;;:::i;:::-;77374:13;77389;77406:36;77434:7;77406:27;:36::i;:::-;77373:69;;;;77461:8;77453:39;;;;-1:-1:-1;;;77453:39:0;;20481:2:1;77453:39:0;;;20463:21:1;20520:2;20500:18;;;20493:30;-1:-1:-1;;;20539:18:1;;;20532:48;20597:18;;77453:39:0;20279:342:1;77453:39:0;77534:7;77505:19;77525:5;77505:26;;;;;;;;:::i;:::-;;;;;;;;;:36;;;;77559:34;;77585:7;;77576;;77559:34;;77505:26;77559:34;77069:532;;;76983:618;;:::o;62025:222::-;62185:10;;:54;;-1:-1:-1;;;62185:54:0;;-1:-1:-1;;;;;20884:15:1;;;62185:54:0;;;20866:34:1;20936:15;;;20916:18;;;20909:43;20968:18;;;20961:34;;;62160:5:0;;62185:10;;:36;;20801:18:1;;62185:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;77609:330::-;77698:4;77680:15;:22;77672:56;;;;-1:-1:-1;;;77672:56:0;;20131:2:1;77672:56:0;;;20113:21:1;20170:2;20150:18;;;20143:30;-1:-1:-1;;;20189:18:1;;;20182:51;20250:18;;77672:56:0;19929:345:1;77672:56:0;77740:10;77752:13;77769:33;77797:4;77769:27;:33::i;:::-;77739:63;;;;77821:5;77813:36;;;;-1:-1:-1;;;77813:36:0;;20481:2:1;77813:36:0;;;20463:21:1;20520:2;20500:18;;;20493:30;-1:-1:-1;;;20539:18:1;;;20532:48;20597:18;;77813:36:0;20279:342:1;77813:36:0;77862:27;77883:5;77862:20;:27::i;:::-;77907:24;;77926:4;;77907:24;;;;;77661:278;;77609:330;:::o;63057:458::-;63119:14;63024:17;-1:-1:-1;;;;;63011:30:0;63169:10;63011:30;63146:362;;-1:-1:-1;;;63403:14:0;63399:23;63386:37;63382:2;63378:46;63057:458;:::o;63146:362::-;-1:-1:-1;14435:10:0;;87994:187::o;24148:295::-;24279:4;24296:15;24314:12;:10;:12::i;:::-;24296:30;;24337:38;24353:4;24359:7;24368:6;24337:15;:38::i;:::-;24386:27;24396:4;24402:2;24406:6;24386:9;:27::i;47537:527::-;47626:22;47634:4;47640:7;47626;:22::i;:::-;47621:436;;47814:52;47853:7;-1:-1:-1;;;;;47814:52:0;47863:2;47814:30;:52::i;:::-;47939:49;47978:4;47985:2;47939:30;:49::i;:::-;47719:292;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;47719:292:0;;;;;;;;;;-1:-1:-1;;;47665:380:0;;;;;;;:::i;57232:108::-;56959:7;;;;57291:41;;;;-1:-1:-1;;;57291:41:0;;22277:2:1;57291:41:0;;;22259:21:1;22316:2;22296:18;;;22289:30;-1:-1:-1;;;22335:18:1;;;22328:50;22395:18;;57291:41:0;22075:344:1;57291:41:0;57232:108::o;91590:581::-;56959:7;;;;91767:9;91759:56;;;;-1:-1:-1;;;91759:56:0;;22626:2:1;91759:56:0;;;22608:21:1;22665:2;22645:18;;;22638:30;22704:34;22684:18;;;22677:62;-1:-1:-1;;;22755:18:1;;;22748:32;22797:19;;91759:56:0;22424:398:1;91759:56:0;-1:-1:-1;;;;;54343:16:0;;54319:4;54343:16;;;:7;:16;;;;;;;;91834:13;91826:60;;;;-1:-1:-1;;;91826:60:0;;23029:2:1;91826:60:0;;;23011:21:1;23068:2;23048:18;;;23041:30;23107:34;23087:18;;;23080:62;-1:-1:-1;;;23158:18:1;;;23151:32;23200:19;;91826:60:0;22827:398:1;91826:60:0;91899:44;91926:4;91932:2;91936:6;91899:26;:44::i;:::-;91968:10;;-1:-1:-1;;;;;91968:10:0;91960:33;91956:208;;92036:35;92054:4;92060:2;92064:6;92036:17;:35::i;:::-;92010:142;;;;-1:-1:-1;;;92010:142:0;;23432:2:1;92010:142:0;;;23414:21:1;23471:2;23451:18;;;23444:30;23510:34;23490:18;;;23483:62;-1:-1:-1;;;23561:18:1;;;23554:43;23614:19;;92010:142:0;23230:409:1;74562:929:0;74675:12;;74651:7;;74675:17;;74671:58;;-1:-1:-1;74716:1:0;74709:8;;74671:58;74782:12;;74741:11;;74807:435;74820:4;74814:3;:10;74807:435;;;74841:11;74855:34;74879:3;74884:4;74855:23;:34::i;:::-;74841:48;;75123:7;75110:5;75116:3;75110:10;;;;;;;;:::i;:::-;;;;;;;;;:20;75106:125;;;75158:3;75151:10;;75106:125;;;75208:7;:3;75214:1;75208:7;:::i;:::-;75202:13;;75106:125;74826:416;74807:435;;;75368:1;75362:3;:7;:36;;;;-1:-1:-1;75391:7:0;75373:5;75379:7;75385:1;75379:3;:7;:::i;:::-;75373:14;;;;;;;;:::i;:::-;;;;;;;;;:25;75362:36;75358:126;;;75422:7;75428:1;75422:3;:7;:::i;:::-;75415:14;;;;;;75358:126;-1:-1:-1;75469:3:0;-1:-1:-1;75462:10:0;;57047:108;56959:7;;;;57117:9;57109:38;;;;-1:-1:-1;;;57109:38:0;;23846:2:1;57109:38:0;;;23828:21:1;23885:2;23865:18;;;23858:30;-1:-1:-1;;;23904:18:1;;;23897:46;23960:18;;57109:38:0;23644:340:1;82274:336:0;82374:4;82380:7;82410:9;82405:170;82429:19;:26;82425:30;;82405:170;;;82507:4;82481:19;82501:1;82481:22;;;;;;;;:::i;:::-;;;;;;;;;:30;82477:87;;82540:4;;82546:1;;-1:-1:-1;82274:336:0;-1:-1:-1;;82274:336:0:o;82477:87::-;82457:3;;;;:::i;:::-;;;;82405:170;;;-1:-1:-1;82593:5:0;;;;-1:-1:-1;82274:336:0;-1:-1:-1;;82274:336:0:o;14279:70::-;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;33043:248::-;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;:::-;33208:9:::1;:21:::0;;-1:-1:-1;;33208:21:0::1;;::::0;::::1;;::::0;;33240:7:::1;:18;33250:8:::0;33240:7;:18:::1;:::i;:::-;-1:-1:-1::0;33269:5:0::1;:14;33277:6:::0;33269:5;:14:::1;:::i;20784:162::-:0;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;:::-;20897:5:::1;:13;20905:5:::0;20897;:13:::1;:::i;:::-;-1:-1:-1::0;20921:7:0::1;:17;20931:7:::0;20921;:17:::1;:::i;56165:97::-:0;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;:::-;56239:7:::1;:15:::0;;-1:-1:-1;;56239:15:0::1;::::0;;56165:97::o;76519:101::-;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;:::-;76611:1:::1;76592:16;:20:::0;76519:101::o;85480:341::-;12692:13;;;;;;;12684:69;;;;-1:-1:-1;;;12684:69:0;;;;;;;:::i;:::-;85564:37:::1;45830:4;85595:5:::0;85564:10:::1;:37::i;:::-;85612:32;-1:-1:-1::0;;;;;;;;;;;85638:5:0::1;85612:10;:32::i;:::-;85655:30;52964:24;85679:5;85655:10;:30::i;:::-;85696;52723:24;85720:5;85696:10;:30::i;:::-;85737;-1:-1:-1::0;;;;;;;;;;;85761:5:0::1;85737:10;:30::i;:::-;85778:35;-1:-1:-1::0;;;;;;;;;;;85807:5:0::1;85778:10;:35::i;83466:212::-:0;83559:19;83593:26;;:30;;83622:1;;83593:30;:::i;:::-;83559:75;;;;;;;;:::i;:::-;;;;;;;;;83530:19;83550:5;83530:26;;;;;;;;:::i;:::-;;;;;;;;;;:104;83645:19;:25;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;83466:212;:::o;29889:453::-;30024:24;30051:25;30061:5;30068:7;30051:9;:25::i;:::-;30024:52;;-1:-1:-1;;30091:16:0;:37;30087:248;;30173:6;30153:16;:26;;30145:68;;;;-1:-1:-1;;;30145:68:0;;24463:2:1;30145:68:0;;;24445:21:1;24502:2;24482:18;;;24475:30;24541:31;24521:18;;;24514:59;24590:18;;30145:68:0;24261:353:1;30145:68:0;30257:51;30266:5;30273:7;30301:6;30282:16;:25;30257:8;:51::i;40285:451::-;40360:13;40386:19;40418:10;40422:6;40418:1;:10;:::i;:::-;:14;;40431:1;40418:14;:::i;:::-;40408:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;40408:25:0;;40386:47;;-1:-1:-1;;;40444:6:0;40451:1;40444:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;40444:15:0;;;;;;;;;-1:-1:-1;;;40470:6:0;40477:1;40470:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;40470:15:0;;;;;;;;-1:-1:-1;40501:9:0;40513:10;40517:6;40513:1;:10;:::i;:::-;:14;;40526:1;40513:14;:::i;:::-;40501:26;;40496:135;40533:1;40529;:5;40496:135;;;-1:-1:-1;;;40581:5:0;40589:3;40581:11;40568:25;;;;;;;:::i;:::-;;;;40556:6;40563:1;40556:9;;;;;;;;:::i;:::-;;;;:37;-1:-1:-1;;;;;40556:37:0;;;;;;;;-1:-1:-1;40618:1:0;40608:11;;;;;40536:3;;;:::i;:::-;;;40496:135;;;-1:-1:-1;40649:10:0;;40641:55;;;;-1:-1:-1;;;40641:55:0;;25135:2:1;40641:55:0;;;25117:21:1;;;25154:18;;;25147:30;25213:34;25193:18;;;25186:62;25265:18;;40641:55:0;24933:356:1;78864:704:0;79064:21;:19;:21::i;:::-;-1:-1:-1;;;;;79100:18:0;;;79096:465;;79178:28;79201:4;79178:22;:28::i;:::-;-1:-1:-1;;;;;79225:16:0;;;79221:206;;79291:26;79314:2;79291:22;:26::i;79221:206::-;79383:28;:26;:28::i;79096:465::-;79480:26;79503:2;79480:22;:26::i;61590:203::-;61740:10;;:45;;-1:-1:-1;;;61740:45:0;;-1:-1:-1;;;;;20884:15:1;;;61740:45:0;;;20866:34:1;20936:15;;;20916:18;;;20909:43;20968:18;;;20961:34;;;61716:4:0;;61740:10;;:27;;20801:18:1;;61740:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;65656:156::-;65718:7;65793:11;65803:1;65794:5;;;65793:11;:::i;:::-;65783:21;;65784:5;;;65783:21;:::i;50763:112::-;50842:25;50853:4;50859:7;50842:10;:25::i;81673:222::-;81724:12;81739:38;:36;:38::i;:::-;81724:53;-1:-1:-1;81792:8:0;;81788:100;;81817:16;:23;;;81855:21;:19;:21::i;81071:146::-;-1:-1:-1;;;;;81155:33:0;;;;;;:24;:33;;;;;;;;22408:9;:18;;;;;;;81139:70;;81155:33;81139:15;:70::i;81190:18::-;81139:15;:70::i;81225:118::-;81282:53;81298:21;81321:13;22224:12;;;22136:108;82618:534;82744:19;:26;82715:7;;82744:31;;82740:45;;-1:-1:-1;82784:1:0;;82618:534::o;82740:45::-;82796:18;82834:9;82829:288;82853:19;:26;82849:30;;82829:288;;;82949:15;82923:19;82943:1;82923:22;;;;;;;;:::i;:::-;;;;;;;;;:41;;:97;;;;;83010:10;82985:19;83005:1;82985:22;;;;;;;;:::i;:::-;;;;;;;;;:35;82923:97;82901:205;;;83068:19;83088:1;83068:22;;;;;;;;:::i;:::-;;;;;;;;;83055:35;;82901:205;82881:3;;;;:::i;:::-;;;;82829:288;;83160:298;83210:9;83234:217;83245:19;:26;83241:30;;83234:217;;;83318:15;83292:19;83312:1;83292:22;;;;;;;;:::i;:::-;;;;;;;;;:41;83288:152;;83354:23;83375:1;83354:20;:23::i;:::-;83234:217;;83288:152;83418:6;83423:1;83418:6;;:::i;:::-;;;83234:217;;81351:314;81460:15;81478:21;81992:16;;;81903:113;81478:21;81460:39;-1:-1:-1;81460:39:0;81514:28;81528:9;81514:13;:28::i;:::-;:38;81510:148;;;81569:27;;;;;;;;-1:-1:-1;81569:27:0;;;;;;;;;;;;;;81611:16;;;:35;;;;;;;;;;;;;;;81351:314::o;82024:242::-;82148:10;;82119:7;;82148:15;;82144:115;;-1:-1:-1;82187:1:0;;82024:242;-1:-1:-1;82024:242:0:o;82144:115::-;82232:10;;82228:3;;82232:14;;82245:1;;82232:14;:::i;:::-;82228:19;;;;;;;;:::i;:::-;;;;;;;;;82221:26;;82024:242;;;:::o;14:286:1:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:1;;209:43;;199:71;;266:1;263;256:12;497:250;582:1;592:113;606:6;603:1;600:13;592:113;;;682:11;;;676:18;663:11;;;656:39;628:2;621:10;592:113;;;-1:-1:-1;;739:1:1;721:16;;714:27;497:250::o;752:396::-;901:2;890:9;883:21;864:4;933:6;927:13;976:6;971:2;960:9;956:18;949:34;992:79;1064:6;1059:2;1048:9;1044:18;1039:2;1031:6;1027:15;992:79;:::i;:::-;1132:2;1111:15;-1:-1:-1;;1107:29:1;1092:45;;;;1139:2;1088:54;;752:396;-1:-1:-1;;752:396:1:o;1153:131::-;-1:-1:-1;;;;;1228:31:1;;1218:42;;1208:70;;1274:1;1271;1264:12;1289:315;1357:6;1365;1418:2;1406:9;1397:7;1393:23;1389:32;1386:52;;;1434:1;1431;1424:12;1386:52;1473:9;1460:23;1492:31;1517:5;1492:31;:::i;:::-;1542:5;1594:2;1579:18;;;;1566:32;;-1:-1:-1;;;1289:315:1:o;1791:456::-;1868:6;1876;1884;1937:2;1925:9;1916:7;1912:23;1908:32;1905:52;;;1953:1;1950;1943:12;1905:52;1992:9;1979:23;2011:31;2036:5;2011:31;:::i;:::-;2061:5;-1:-1:-1;2118:2:1;2103:18;;2090:32;2131:33;2090:32;2131:33;:::i;:::-;1791:456;;2183:7;;-1:-1:-1;;;2237:2:1;2222:18;;;;2209:32;;1791:456::o;2434:180::-;2493:6;2546:2;2534:9;2525:7;2521:23;2517:32;2514:52;;;2562:1;2559;2552:12;2514:52;-1:-1:-1;2585:23:1;;2434:180;-1:-1:-1;2434:180:1:o;2619:315::-;2687:6;2695;2748:2;2736:9;2727:7;2723:23;2719:32;2716:52;;;2764:1;2761;2754:12;2716:52;2800:9;2787:23;2777:33;;2860:2;2849:9;2845:18;2832:32;2873:31;2898:5;2873:31;:::i;:::-;2923:5;2913:15;;;2619:315;;;;;:::o;3128:383::-;3205:6;3213;3221;3274:2;3262:9;3253:7;3249:23;3245:32;3242:52;;;3290:1;3287;3280:12;3242:52;3329:9;3316:23;3348:31;3373:5;3348:31;:::i;:::-;3398:5;3450:2;3435:18;;3422:32;;-1:-1:-1;3501:2:1;3486:18;;;3473:32;;3128:383;-1:-1:-1;;;3128:383:1:o;3516:247::-;3575:6;3628:2;3616:9;3607:7;3603:23;3599:32;3596:52;;;3644:1;3641;3634:12;3596:52;3683:9;3670:23;3702:31;3727:5;3702:31;:::i;4273:127::-;4334:10;4329:3;4325:20;4322:1;4315:31;4365:4;4362:1;4355:15;4389:4;4386:1;4379:15;4405:275;4476:2;4470:9;4541:2;4522:13;;-1:-1:-1;;4518:27:1;4506:40;;4576:18;4561:34;;4597:22;;;4558:62;4555:88;;;4623:18;;:::i;:::-;4659:2;4652:22;4405:275;;-1:-1:-1;4405:275:1:o;4685:187::-;4734:4;4767:18;4759:6;4756:30;4753:56;;;4789:18;;:::i;:::-;-1:-1:-1;4855:2:1;4834:15;-1:-1:-1;;4830:29:1;4861:4;4826:40;;4685:187::o;4877:464::-;4920:5;4973:3;4966:4;4958:6;4954:17;4950:27;4940:55;;4991:1;4988;4981:12;4940:55;5027:6;5014:20;5058:49;5074:32;5103:2;5074:32;:::i;:::-;5058:49;:::i;:::-;5132:2;5123:7;5116:19;5178:3;5171:4;5166:2;5158:6;5154:15;5150:26;5147:35;5144:55;;;5195:1;5192;5185:12;5144:55;5260:2;5253:4;5245:6;5241:17;5234:4;5225:7;5221:18;5208:55;5308:1;5283:16;;;5301:4;5279:27;5272:38;;;;5287:7;4877:464;-1:-1:-1;;;4877:464:1:o;5346:322::-;5415:6;5468:2;5456:9;5447:7;5443:23;5439:32;5436:52;;;5484:1;5481;5474:12;5436:52;5524:9;5511:23;5557:18;5549:6;5546:30;5543:50;;;5589:1;5586;5579:12;5543:50;5612;5654:7;5645:6;5634:9;5630:22;5612:50;:::i;5673:114::-;5757:4;5750:5;5746:16;5739:5;5736:27;5726:55;;5777:1;5774;5767:12;5792:243;5849:6;5902:2;5890:9;5881:7;5877:23;5873:32;5870:52;;;5918:1;5915;5908:12;5870:52;5957:9;5944:23;5976:29;5999:5;5976:29;:::i;6312:1080::-;6447:6;6455;6463;6471;6479;6532:3;6520:9;6511:7;6507:23;6503:33;6500:53;;;6549:1;6546;6539:12;6500:53;6588:9;6575:23;6607:31;6632:5;6607:31;:::i;:::-;6657:5;-1:-1:-1;6713:2:1;6698:18;;6685:32;6736:18;6766:14;;;6763:34;;;6793:1;6790;6783:12;6763:34;6816:50;6858:7;6849:6;6838:9;6834:22;6816:50;:::i;:::-;6806:60;;6919:2;6908:9;6904:18;6891:32;6875:48;;6948:2;6938:8;6935:16;6932:36;;;6964:1;6961;6954:12;6932:36;6987:52;7031:7;7020:8;7009:9;7005:24;6987:52;:::i;:::-;6977:62;;7092:2;7081:9;7077:18;7064:32;7048:48;;7121:2;7111:8;7108:16;7105:36;;;7137:1;7134;7127:12;7105:36;7160:52;7204:7;7193:8;7182:9;7178:24;7160:52;:::i;:::-;7150:62;;7265:3;7254:9;7250:19;7237:33;7221:49;;7295:2;7285:8;7282:16;7279:36;;;7311:1;7308;7301:12;7279:36;;7334:52;7378:7;7367:8;7356:9;7352:24;7334:52;:::i;:::-;7324:62;;;6312:1080;;;;;;;;:::o;7397:248::-;7465:6;7473;7526:2;7514:9;7505:7;7501:23;7497:32;7494:52;;;7542:1;7539;7532:12;7494:52;-1:-1:-1;;7565:23:1;;;7635:2;7620:18;;;7607:32;;-1:-1:-1;7397:248:1:o;7650:388::-;7718:6;7726;7779:2;7767:9;7758:7;7754:23;7750:32;7747:52;;;7795:1;7792;7785:12;7747:52;7834:9;7821:23;7853:31;7878:5;7853:31;:::i;:::-;7903:5;-1:-1:-1;7960:2:1;7945:18;;7932:32;7973:33;7932:32;7973:33;:::i;8043:632::-;8214:2;8266:21;;;8336:13;;8239:18;;;8358:22;;;8185:4;;8214:2;8437:15;;;;8411:2;8396:18;;;8185:4;8480:169;8494:6;8491:1;8488:13;8480:169;;;8555:13;;8543:26;;8624:15;;;;8589:12;;;;8516:1;8509:9;8480:169;;;-1:-1:-1;8666:3:1;;8043:632;-1:-1:-1;;;;;;8043:632:1:o;8908:380::-;8987:1;8983:12;;;;9030;;;9051:61;;9105:4;9097:6;9093:17;9083:27;;9051:61;9158:2;9150:6;9147:14;9127:18;9124:38;9121:161;;9204:10;9199:3;9195:20;9192:1;9185:31;9239:4;9236:1;9229:15;9267:4;9264:1;9257:15;9709:127;9770:10;9765:3;9761:20;9758:1;9751:31;9801:4;9798:1;9791:15;9825:4;9822:1;9815:15;9841:125;9906:9;;;9927:10;;;9924:36;;;9940:18;;:::i;10503:545::-;10605:2;10600:3;10597:11;10594:448;;;10641:1;10666:5;10662:2;10655:17;10711:4;10707:2;10697:19;10781:2;10769:10;10765:19;10762:1;10758:27;10752:4;10748:38;10817:4;10805:10;10802:20;10799:47;;;-1:-1:-1;10840:4:1;10799:47;10895:2;10890:3;10886:12;10883:1;10879:20;10873:4;10869:31;10859:41;;10950:82;10968:2;10961:5;10958:13;10950:82;;;11013:17;;;10994:1;10983:13;10950:82;;11224:1352;11350:3;11344:10;11377:18;11369:6;11366:30;11363:56;;;11399:18;;:::i;:::-;11428:97;11518:6;11478:38;11510:4;11504:11;11478:38;:::i;:::-;11472:4;11428:97;:::i;:::-;11580:4;;11644:2;11633:14;;11661:1;11656:663;;;;12363:1;12380:6;12377:89;;;-1:-1:-1;12432:19:1;;;12426:26;12377:89;-1:-1:-1;;11181:1:1;11177:11;;;11173:24;11169:29;11159:40;11205:1;11201:11;;;11156:57;12479:81;;11626:944;;11656:663;10450:1;10443:14;;;10487:4;10474:18;;-1:-1:-1;;11692:20:1;;;11810:236;11824:7;11821:1;11818:14;11810:236;;;11913:19;;;11907:26;11892:42;;12005:27;;;;11973:1;11961:14;;;;11840:19;;11810:236;;;11814:3;12074:6;12065:7;12062:19;12059:201;;;12135:19;;;12129:26;-1:-1:-1;;12218:1:1;12214:14;;;12230:3;12210:24;12206:37;12202:42;12187:58;12172:74;;12059:201;-1:-1:-1;;;;;12306:1:1;12290:14;;;12286:22;12273:36;;-1:-1:-1;11224:1352:1:o;12581:289::-;12712:3;12750:6;12744:13;12766:66;12825:6;12820:3;12813:4;12805:6;12801:17;12766:66;:::i;:::-;12848:16;;;;;12581:289;-1:-1:-1;;12581:289:1:o;15808:127::-;15869:10;15864:3;15860:20;15857:1;15850:31;15900:4;15897:1;15890:15;15924:4;15921:1;15914:15;16745:128;16812:9;;;16833:11;;;16830:37;;;16847:18;;:::i;16878:649::-;16958:6;17011:2;16999:9;16990:7;16986:23;16982:32;16979:52;;;17027:1;17024;17017:12;16979:52;17060:9;17054:16;17093:18;17085:6;17082:30;17079:50;;;17125:1;17122;17115:12;17079:50;17148:22;;17201:4;17193:13;;17189:27;-1:-1:-1;17179:55:1;;17230:1;17227;17220:12;17179:55;17259:2;17253:9;17284:49;17300:32;17329:2;17300:32;:::i;17284:49::-;17356:2;17349:5;17342:17;17396:7;17391:2;17386;17382;17378:11;17374:20;17371:33;17368:53;;;17417:1;17414;17407:12;17368:53;17430:67;17494:2;17489;17482:5;17478:14;17473:2;17469;17465:11;17430:67;:::i;17891:404::-;18093:2;18075:21;;;18132:2;18112:18;;;18105:30;18171:34;18166:2;18151:18;;18144:62;-1:-1:-1;;;18237:2:1;18222:18;;18215:38;18285:3;18270:19;;17891:404::o;19517:407::-;19719:2;19701:21;;;19758:2;19738:18;;;19731:30;19797:34;19792:2;19777:18;;19770:62;-1:-1:-1;;;19863:2:1;19848:18;;19841:41;19914:3;19899:19;;19517:407::o;21006:247::-;21074:6;21127:2;21115:9;21106:7;21102:23;21098:32;21095:52;;;21143:1;21140;21133:12;21095:52;21175:9;21169:16;21194:29;21217:5;21194:29;:::i;21258:812::-;21669:25;21664:3;21657:38;21639:3;21724:6;21718:13;21740:75;21808:6;21803:2;21798:3;21794:12;21787:4;21779:6;21775:17;21740:75;:::i;:::-;-1:-1:-1;;;21874:2:1;21834:16;;;21866:11;;;21859:40;21924:13;;21946:76;21924:13;22008:2;22000:11;;21993:4;21981:17;;21946:76;:::i;:::-;22042:17;22061:2;22038:26;;21258:812;-1:-1:-1;;;;21258:812:1:o;23989:135::-;24028:3;24049:17;;;24046:43;;24069:18;;:::i;:::-;-1:-1:-1;24116:1:1;24105:13;;23989:135::o;24129:127::-;24190:10;24185:3;24181:20;24178:1;24171:31;24221:4;24218:1;24211:15;24245:4;24242:1;24235:15;24619:168;24692:9;;;24723;;24740:15;;;24734:22;;24720:37;24710:71;;24761:18;;:::i;24792:136::-;24831:3;24859:5;24849:39;;24868:18;;:::i;:::-;-1:-1:-1;;;24904:18:1;;24792:136::o;25294:277::-;25361:6;25414:2;25402:9;25393:7;25389:23;25385:32;25382:52;;;25430:1;25427;25420:12;25382:52;25462:9;25456:16;25515:5;25508:13;25501:21;25494:5;25491:32;25481:60;;25537:1;25534;25527:12;25576:217;25616:1;25642;25632:132;;25686:10;25681:3;25677:20;25674:1;25667:31;25721:4;25718:1;25711:15;25749:4;25746:1;25739:15;25632:132;-1:-1:-1;25778:9:1;;25576:217::o

Swarm Source

ipfs://a909904b22cdfda408a2defda054c455be54767f3c6f55aab9e1cc5736ee0044
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.