Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DigitalAsset
Compiler Version
v0.8.30+commit.73712a01
Contract Source Code (Solidity)
/**
*Submitted for verification at basescan.org on 2025-07-15
*/
// SPDX-License-Identifier: MIT
// File: @openzeppelin/contracts/utils/introspection/IERC165.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC 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/token/ERC721/IERC721.sol
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
// File: @openzeppelin/contracts/utils/Context.sol
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
// File: @openzeppelin/contracts/access/Ownable.sol
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// File: @openzeppelin/contracts/utils/Errors.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}
// File: @openzeppelin/contracts/utils/Address.sol
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// 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
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
// File: @openzeppelin/contracts/utils/introspection/ERC165.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
// File: @openzeppelin/contracts/utils/Comparators.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to compare values.
*
* _Available since v5.1._
*/
library Comparators {
function lt(uint256 a, uint256 b) internal pure returns (bool) {
return a < b;
}
function gt(uint256 a, uint256 b) internal pure returns (bool) {
return a > b;
}
}
// File: @openzeppelin/contracts/utils/SlotDerivation.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
pragma solidity ^0.8.20;
/**
* @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
* corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
* the solidity language / compiler.
*
* See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
*
* Example usage:
* ```solidity
* contract Example {
* // Add the library methods
* using StorageSlot for bytes32;
* using SlotDerivation for bytes32;
*
* // Declare a namespace
* string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot
*
* function setValueInNamespace(uint256 key, address newValue) internal {
* _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
* }
*
* function getValueInNamespace(uint256 key) internal view returns (address) {
* return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
* }
* }
* ```
*
* TIP: Consider using this library along with {StorageSlot}.
*
* NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
* upgrade safety will ignore the slots accessed through this library.
*
* _Available since v5.1._
*/
library SlotDerivation {
/**
* @dev Derive an ERC-7201 slot from a string (namespace).
*/
function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
assembly ("memory-safe") {
mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
slot := and(keccak256(0x00, 0x20), not(0xff))
}
}
/**
* @dev Add an offset to a slot to get the n-th element of a structure or an array.
*/
function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
unchecked {
return bytes32(uint256(slot) + pos);
}
}
/**
* @dev Derive the location of the first element in an array from the slot where the length is stored.
*/
function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, slot)
result := keccak256(0x00, 0x20)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, and(key, shr(96, not(0))))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, iszero(iszero(key)))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
}
// File: @openzeppelin/contracts/utils/StorageSlot.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}
// File: @openzeppelin/contracts/utils/Panic.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}
// File: @openzeppelin/contracts/utils/math/SafeCast.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}
// File: @openzeppelin/contracts/utils/math/Math.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* 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 {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, 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.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
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⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// 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²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev 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) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
// File: @openzeppelin/contracts/utils/Arrays.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using SlotDerivation for bytes32;
using StorageSlot for bytes32;
/**
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
uint256[] memory array,
function(uint256, uint256) pure returns (bool) comp
) internal pure returns (uint256[] memory) {
_quickSort(_begin(array), _end(array), comp);
return array;
}
/**
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
*/
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
sort(array, Comparators.lt);
return array;
}
/**
* @dev Sort an array of address (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
address[] memory array,
function(address, address) pure returns (bool) comp
) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of address in increasing order.
*/
function sort(address[] memory array) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
bytes32[] memory array,
function(bytes32, bytes32) pure returns (bool) comp
) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
*/
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
* at end (exclusive). Sorting follows the `comp` comparator.
*
* Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
*
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
* be used only if the limits are within a memory array.
*/
function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
unchecked {
if (end - begin < 0x40) return;
// Use first element as pivot
uint256 pivot = _mload(begin);
// Position where the pivot should be at the end of the loop
uint256 pos = begin;
for (uint256 it = begin + 0x20; it < end; it += 0x20) {
if (comp(_mload(it), pivot)) {
// If the value stored at the iterator's position comes before the pivot, we increment the
// position of the pivot and move the value there.
pos += 0x20;
_swap(pos, it);
}
}
_swap(begin, pos); // Swap pivot into place
_quickSort(begin, pos, comp); // Sort the left side of the pivot
_quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
}
}
/**
* @dev Pointer to the memory location of the first element of `array`.
*/
function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
assembly ("memory-safe") {
ptr := add(array, 0x20)
}
}
/**
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
* that comes just after the last element of the array.
*/
function _end(uint256[] memory array) private pure returns (uint256 ptr) {
unchecked {
return _begin(array) + array.length * 0x20;
}
}
/**
* @dev Load memory word (as a uint256) at location `ptr`.
*/
function _mload(uint256 ptr) private pure returns (uint256 value) {
assembly {
value := mload(ptr)
}
}
/**
* @dev Swaps the elements memory location `ptr1` and `ptr2`.
*/
function _swap(uint256 ptr1, uint256 ptr2) private pure {
assembly {
let value1 := mload(ptr1)
let value2 := mload(ptr2)
mstore(ptr1, value2)
mstore(ptr2, value1)
}
}
/// @dev Helper: low level cast address memory array to uint256 memory array
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast address comp function to uint256 comp function
function _castToUint256Comp(
function(address, address) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
function _castToUint256Comp(
function(bytes32, bytes32) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/**
* @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).
*
* NOTE: The `array` is expected to be sorted in ascending order, and to
* contain no repeated elements.
*
* IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
* support for repeated elements in the array. The {lowerBound} function should
* be used instead.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.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 towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > 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 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value greater or equal than `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).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
*/
function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.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 towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value strictly greater than `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).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
*/
function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.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 towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Same as {lowerBound}, but with an array in memory.
*/
function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.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 towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Same as {upperBound}, but with an array in memory.
*/
function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.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 towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(address[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(uint256[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
}
// File: @openzeppelin/contracts/utils/structs/EnumerableSet.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
* - Set can be cleared (all elements removed) in O(n).
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function _clear(Set storage set) private {
uint256 len = _length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(Bytes32Set storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(AddressSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(UintSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}
// File: contracts/MONFT.sol
pragma solidity ^0.8.20;
contract MultiOwnerNFT is Context, ERC165, IERC721, Ownable {
using Address for address;
using EnumerableSet for EnumerableSet.AddressSet; // Use EnumerableSet for address sets
uint256 private _nextTokenId;
// Replace array with EnumerableSet for owners
mapping(uint256 => EnumerableSet.AddressSet) internal _owners;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
mapping(address => uint256) private _balances;
// Mapping to track archived status for each token-owner pair
mapping(uint256 => mapping(address => bool)) private _archivedStatus;
// Modifier to check if the owner has archived the token's transfer ability
modifier isNotArchived(uint256 tokenId, address owner) {
require(
!_archivedStatus[tokenId][owner],
"MO-NFT: Owner's transfer ability is archived for this token"
);
_;
}
event TokenMinted(uint256 tokenId, address owner);
event TokenTransferred(uint256 tokenId, address from, address to);
// Emit an event when the archived status is updated for a specific owner
event ArchivedStatusUpdated(
uint256 indexed tokenId,
address indexed owner,
bool archived
);
constructor(address owner) Ownable(owner) {}
function mintToken() public returns (uint256) {
_nextTokenId++;
// Add the sender to the set of owners for the new token
_owners[_nextTokenId].add(_msgSender());
// Increment the balance of the owner
_balances[_msgSender()] += 1;
emit TokenMinted(_nextTokenId, _msgSender());
return _nextTokenId;
}
function isOwner(
uint256 tokenId,
address account
) public view returns (bool) {
require(_exists(tokenId), "MO-NFT: Token does not exist");
// Check if the account is in the owners set for the token
return _owners[tokenId].contains(account);
}
function _exists(uint256 tokenId) internal view returns (bool) {
return _owners[tokenId].length() > 0;
}
// IERC721 Functions
function totalSupply() public view returns (uint256) {
return _nextTokenId;
}
function balanceOf(
address owner
) external view override returns (uint256 balance) {
require(
owner != address(0),
"MO-NFT: Balance query for the zero address"
);
// Return the balance from the _balances mapping
return _balances[owner];
}
function ownerOf(
uint256 tokenId
) external view override returns (address owner) {
require(_exists(tokenId), "MO-NFT: Owner query for nonexistent token");
// Return the first owner in the set (since this is an EnumerableSet, order is not guaranteed)
return _owners[tokenId].at(0);
}
function getOwnersCount(uint256 tokenId) public view returns (uint256) {
require(_exists(tokenId), "MO-NFT: Token does not exist");
// Return the number of owners for the given tokenId
return EnumerableSet.length(_owners[tokenId]);
}
// Public function to check if a specific owner has archived their transfer ability for a token
function isArchived(
uint256 tokenId,
address owner
) external view returns (bool) {
return _archivedStatus[tokenId][owner];
}
// Overrides for approvals
function approve(address /* to */, uint256 /* tokenId */) public pure override {
revert("MO-NFT: approvals not supported");
}
function setApprovalForAll(
address /* operator */,
bool /* approved */
) public pure override {
revert("MO-NFT: approvals not supported");
}
function getApproved(
uint256 /* tokenId */
) public pure override returns (address) {
revert("MO-NFT: approvals not supported");
}
function isApprovedForAll(
address /* owner */,
address /* operator */
) public pure override returns (bool) {
revert("MO-NFT: approvals not supported");
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override isNotArchived(tokenId, from) {
require(
isOwner(tokenId, _msgSender()),
"MO-NFT: Transfer from incorrect account"
);
require(to != address(0), "MO-NFT: Transfer to the zero address");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public override isNotArchived(tokenId, from) {
// 1. Perform the multi-owner transfer logic
transferFrom(from, to, tokenId);
// 2. Call the internal function to check if `to` can handle ERC-721 tokens
require(
_checkOnERC721Received(from, to, tokenId, ""),
"MO-NFT: transfer to non ERC721Receiver implementer"
);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public override isNotArchived(tokenId, from) {
// 1. Perform the multi-owner transfer logic
transferFrom(from, to, tokenId);
// 2. Call the internal function to check if `to` can handle ERC-721 tokens
require(
_checkOnERC721Received(from, to, tokenId, _data),
"MO-NFT: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Private helper to call `onERC721Received` on a target contract.
* Returns true if the target contract returns the correct function selector.
*/
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
// If `to` is not a contract, there's nothing to check.
if (to.code.length == 0) {
return true;
}
try
IERC721Receiver(to).onERC721Received(
msg.sender,
from,
tokenId,
_data
)
returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("MO-NFT: transfer to non ERC721Receiver implementer");
} else {
// Bubble up any custom revert reason returned by the contract call
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
function _transfer(address from, address to, uint256 tokenId) internal {
require(
isOwner(tokenId, from),
"MO-NFT: Transfer from incorrect owner"
);
require(to != address(0), "MO-NFT: Transfer to the zero address");
require(!isOwner(tokenId, to), "MO-NFT: Recipient is already an owner");
// Add the new owner to the EnumerableSet
_owners[tokenId].add(to);
// Update balances
_balances[to] += 1;
emit TokenTransferred(tokenId, from, to);
}
// Function to update the archived status for a specific owner of a token (permanent change)
function archive(uint256 tokenId) external {
require(
isOwner(tokenId, msg.sender),
"MO-NFT: Caller is not the owner of this token"
);
// Once archived, the status cannot be reversed
require(
_archivedStatus[tokenId][msg.sender] == false,
"MO-NFT: Token can only be archived once for an owner"
);
_archivedStatus[tokenId][msg.sender] = true;
emit ArchivedStatusUpdated(tokenId, msg.sender, true);
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
super.supportsInterface(interfaceId);
}
}
// File: contracts/IDigitalAsset.sol
pragma solidity ^0.8.20;
interface IDigitalAsset {
function getAssetsTotalSupply() external view returns (uint256);
function getAssetName(uint256 assetId) external view returns (string memory);
function getAssetDetails(uint256 assetId) external view returns (AssetDetails memory);
// Define the structure here as well if you wish to use it as a return type
struct AssetDetails {
uint256 assetId;
string assetName;
uint256 size;
bytes32 fileHash;
address provider;
uint256 transferValue;
}
// Direct minting by provider/author - the only minting method
function provide(
string memory assetName,
uint256 size,
bytes32 fileHash,
uint256 transferValue
) external payable returns (uint256);
// Platform fee management
function setPlatformFeeRatio(uint256 newRatio) external;
function setPlatformFeeRecipient(address newRecipient) external;
function getPlatformFeeRatio() external view returns (uint256);
function getPlatformFeeRecipient() external view returns (address);
function calculatePlatformFee(uint256 transferValue) external view returns (uint256);
function getTransferCostBreakdown(uint256 assetId, address caller)
external view returns (uint256 providerFee, uint256 platformFee, uint256 totalCost);
// Minting fee management
function setMintingFee(uint256 newFee) external;
function getMintingFee() external view returns (uint256);
// Platform fee configuration (unified view)
function getPlatformFeeConfiguration() external view returns (
uint256 mintingFee,
uint256 transferFeeRatio,
address recipient
);
// Base update value management
function setBaseUpdateValue(uint256 newBaseUpdateValue) external;
function getBaseUpdateValue() external view returns (uint256);
function getUpdateValueCost(uint256 assetId) external view returns (uint256);
// Provider management
function transferProvider(uint256 assetId, address newProvider) external;
function getProvider(uint256 assetId) external view returns (address);
}
// File: contracts/DigitalAsset.sol
pragma solidity ^0.8.20;
contract DigitalAsset is MultiOwnerNFT, IDigitalAsset {
struct DigitAssetInfo {
uint256 assetId;
string assetName;
uint256 size;
bytes32 fileHash;
address provider;
uint256 transferValue;
}
mapping(uint256 => DigitAssetInfo) private _assets;
// Platform fee system
uint256 private _platformFeeRatio; // Basis points (e.g., 250 = 2.5%)
address private _platformFeeRecipient; // Address to receive ALL platform fees (minting + transfers)
uint256 private _mintingFee; // Fixed minting fee in wei
uint256 private _baseUpdateValue; // Base fee for updating transfer values (in wei)
uint256 public constant MAX_PLATFORM_FEE_RATIO = 1000; // 10% maximum platform fee
// Events
event AssetProvided(
uint256 indexed assetId,
uint256 indexed size,
address indexed provider,
bytes32 fileHash,
uint256 transferValue
);
event AssetTransferred(
address indexed from,
address indexed to,
uint256 indexed assetId,
uint256 transferValue
);
event TransferValueUpdated(
uint256 indexed assetId,
uint256 oldTransferValue,
uint256 newTransferValue
);
event ProviderFreeTransfer(
uint256 indexed assetId,
address indexed provider,
address indexed to
);
event PlatformFeeUpdated(
uint256 oldRatio,
uint256 newRatio
);
event PlatformFeeRecipientUpdated(
address oldRecipient,
address newRecipient
);
event PlatformFeePaid(
uint256 indexed assetId,
address indexed payer,
uint256 feeAmount
);
event MintingFeeUpdated(
uint256 oldFee,
uint256 newFee
);
event MintingFeePaid(
uint256 indexed assetId,
address indexed payer,
uint256 feeAmount
);
event BaseUpdateValueUpdated(
uint256 oldBaseUpdateValue,
uint256 newBaseUpdateValue
);
event UpdateValueFeePaid(
uint256 indexed assetId,
address indexed provider,
uint256 feeAmount,
uint256 ownersCount
);
event ProviderTransferred(
uint256 indexed assetId,
address indexed oldProvider,
address indexed newProvider
);
constructor() payable MultiOwnerNFT(msg.sender) {
// Initialize platform fee recipient to the contract owner (receives ALL platform fees)
_platformFeeRecipient = msg.sender;
_platformFeeRatio = 250; // Default 2.5% platform fee for transfers
_mintingFee = 0.0005 ether; // Default 0.0005 ETH minting fee
_baseUpdateValue = 0.00001 ether; // Default 0.00001 ETH base update value
}
function getAssetsTotalSupply() public view override returns (uint256) {
return totalSupply();
}
function getAssetName(
uint256 assetId
) public view override returns (string memory) {
require(_exists(assetId), "Asset: Asset does not exist");
return _assets[assetId].assetName;
}
function getAssetDetails(
uint256 assetId
) public view override returns (AssetDetails memory) {
require(_exists(assetId), "Asset: Asset does not exist");
DigitAssetInfo storage asset = _assets[assetId];
return
AssetDetails({
assetId: asset.assetId,
assetName: asset.assetName,
size: asset.size,
fileHash: asset.fileHash,
provider: asset.provider,
transferValue: asset.transferValue
});
}
// Direct minting by provider/author - the only minting method
function provide(
string memory assetName,
uint256 size,
bytes32 fileHash,
uint256 transferValue
) external payable returns (uint256) {
// Require minting fee payment
require(msg.value >= _mintingFee, "Insufficient minting fee");
// Pay minting fee to platform recipient (same address as transfer fees)
if (_mintingFee > 0) {
payable(_platformFeeRecipient).transfer(_mintingFee);
}
// Return excess ETH to sender if any
if (msg.value > _mintingFee) {
payable(msg.sender).transfer(msg.value - _mintingFee);
}
// Provider mints directly to themselves
uint256 assetId = mintToken();
_assets[assetId] = DigitAssetInfo({
assetId: assetId,
assetName: assetName,
size: size,
fileHash: fileHash,
provider: msg.sender, // Caller is the provider
transferValue: transferValue
});
emit AssetProvided(assetId, size, msg.sender, fileHash, transferValue);
emit MintingFeePaid(assetId, msg.sender, _mintingFee);
return assetId;
}
function setTransferValue(
uint256 assetId,
uint256 newTransferValue
) external payable {
require(_exists(assetId), "Asset: Asset does not exist");
DigitAssetInfo storage asset = _assets[assetId];
require(
msg.sender == asset.provider,
"Only provider can update transfer value"
);
// Calculate required fee based on number of owners
uint256 ownersCount = getOwnersCount(assetId);
uint256 requiredFee = _baseUpdateValue * ownersCount;
require(msg.value >= requiredFee, "Insufficient fee for transfer value update");
// Pay the update fee to platform recipient
if (requiredFee > 0) {
payable(_platformFeeRecipient).transfer(requiredFee);
}
// Return excess ETH to sender if any
if (msg.value > requiredFee) {
payable(msg.sender).transfer(msg.value - requiredFee);
}
uint256 oldTransferValue = asset.transferValue;
asset.transferValue = newTransferValue;
emit TransferValueUpdated(assetId, oldTransferValue, newTransferValue);
emit UpdateValueFeePaid(assetId, msg.sender, requiredFee, ownersCount);
}
function transferProvider(
uint256 assetId,
address newProvider
) external {
require(_exists(assetId), "Asset: Asset does not exist");
require(newProvider != address(0), "Asset: New provider cannot be zero address");
DigitAssetInfo storage asset = _assets[assetId];
require(
msg.sender == asset.provider,
"Only current provider can transfer provider role"
);
require(
newProvider != asset.provider,
"Asset: New provider must be different from current provider"
);
address oldProvider = asset.provider;
asset.provider = newProvider;
emit ProviderTransferred(assetId, oldProvider, newProvider);
}
function getProvider(uint256 assetId) external view returns (address) {
require(_exists(assetId), "Asset: Asset does not exist");
return _assets[assetId].provider;
}
// Platform fee management functions (only owner)
function setPlatformFeeRatio(uint256 newRatio) external onlyOwner {
require(newRatio <= MAX_PLATFORM_FEE_RATIO, "Platform fee ratio too high");
uint256 oldRatio = _platformFeeRatio;
_platformFeeRatio = newRatio;
emit PlatformFeeUpdated(oldRatio, newRatio);
}
function setPlatformFeeRecipient(address newRecipient) external onlyOwner {
require(newRecipient != address(0), "Platform fee recipient cannot be zero address");
address oldRecipient = _platformFeeRecipient;
_platformFeeRecipient = newRecipient;
emit PlatformFeeRecipientUpdated(oldRecipient, newRecipient);
}
function getPlatformFeeRatio() external view returns (uint256) {
return _platformFeeRatio;
}
function getPlatformFeeRecipient() external view returns (address) {
return _platformFeeRecipient;
}
function setMintingFee(uint256 newFee) external onlyOwner {
uint256 oldFee = _mintingFee;
_mintingFee = newFee;
emit MintingFeeUpdated(oldFee, newFee);
}
function getMintingFee() external view returns (uint256) {
return _mintingFee;
}
function setBaseUpdateValue(uint256 newBaseUpdateValue) external onlyOwner {
uint256 oldBaseUpdateValue = _baseUpdateValue;
_baseUpdateValue = newBaseUpdateValue;
emit BaseUpdateValueUpdated(oldBaseUpdateValue, newBaseUpdateValue);
}
function getBaseUpdateValue() external view returns (uint256) {
return _baseUpdateValue;
}
function getUpdateValueCost(uint256 assetId) external view returns (uint256) {
require(_exists(assetId), "Asset: Asset does not exist");
uint256 ownersCount = getOwnersCount(assetId);
return _baseUpdateValue * ownersCount;
}
/**
* @dev Get all platform fee configuration in one call
* @return mintingFee Fixed fee for minting (in wei)
* @return transferFeeRatio Platform fee ratio for transfers (in basis points)
* @return recipient Address that receives ALL platform fees (both minting and transfers)
*/
function getPlatformFeeConfiguration() external view returns (
uint256 mintingFee,
uint256 transferFeeRatio,
address recipient
) {
return (_mintingFee, _platformFeeRatio, _platformFeeRecipient);
}
function calculatePlatformFee(uint256 transferValue) public view returns (uint256) {
if (_platformFeeRatio == 0) return 0;
return (transferValue * _platformFeeRatio) / 10000; // Basis points calculation
}
// Check if a transfer would be free for the caller
function isTransferFreeForCaller(
uint256 assetId,
address caller
) external view returns (bool) {
require(_exists(assetId), "Asset: Asset does not exist");
DigitAssetInfo storage asset = _assets[assetId];
// Transfer is free if caller is the provider or transfer value is 0
return (caller == asset.provider || asset.transferValue == 0);
}
// Get the required payment amount for a transfer by a specific caller
function getTransferCost(
uint256 assetId,
address caller
) external view returns (uint256) {
require(_exists(assetId), "Asset: Asset does not exist");
DigitAssetInfo storage asset = _assets[assetId];
// No cost if caller is the provider
if (caller == asset.provider) {
return 0;
}
uint256 providerFee = asset.transferValue;
uint256 platformFee = calculatePlatformFee(providerFee);
return providerFee + platformFee;
}
// Get detailed breakdown of transfer costs
function getTransferCostBreakdown(
uint256 assetId,
address caller
) external view returns (uint256 providerFee, uint256 platformFee, uint256 totalCost) {
require(_exists(assetId), "Asset: Asset does not exist");
DigitAssetInfo storage asset = _assets[assetId];
// No cost if caller is the provider
if (caller == asset.provider) {
return (0, 0, 0);
}
providerFee = asset.transferValue;
platformFee = calculatePlatformFee(providerFee);
totalCost = providerFee + platformFee;
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public override {
require(
isOwner(tokenId, msg.sender), // Ensure that `msg.sender` is an owner
"MO-NFT: Transfer from incorrect account"
);
require(to != address(0), "MO-NFT: Transfer to the zero address");
// Standard ERC721 transfer - no payment required
_transferWithoutPayment(from, to, tokenId);
}
// Payable version for transfers with royalty payments
function transferFromWithPayment(
address from,
address to,
uint256 tokenId
) public payable {
require(
isOwner(tokenId, msg.sender), // Ensure that `msg.sender` is an owner
"MO-NFT: Transfer from incorrect account"
);
require(to != address(0), "MO-NFT: Transfer to the zero address");
_transferWithProviderPayment(from, to, tokenId);
}
// Smart transfer function that automatically chooses free or paid transfer
function smartTransfer(
address from,
address to,
uint256 tokenId
) public payable {
require(
isOwner(tokenId, msg.sender), // Ensure that `msg.sender` is an owner
"MO-NFT: Transfer from incorrect account"
);
require(to != address(0), "MO-NFT: Transfer to the zero address");
// If sender is the provider or transfer value is 0, use free transfer
if (msg.sender == _assets[tokenId].provider || _assets[tokenId].transferValue == 0) {
_transferWithoutPayment(from, to, tokenId);
// Return any sent ETH since no payment is needed
if (msg.value > 0) {
payable(msg.sender).transfer(msg.value);
}
} else {
// Use paid transfer for non-providers
_transferWithProviderPayment(from, to, tokenId);
}
}
function _transferWithoutPayment(
address from,
address to,
uint256 tokenId
) internal {
// Call the internal transfer function in MultiOwnerNFT
_transfer(from, to, tokenId);
emit AssetTransferred(from, to, tokenId, 0); // No payment made
}
function _transferWithProviderPayment(
address from,
address to,
uint256 tokenId
) internal {
DigitAssetInfo storage asset = _assets[tokenId];
// If the sender is the provider (original author), no payment required
if (msg.sender == asset.provider) {
// Provider transfers their own token - no fee required
_transfer(from, to, tokenId);
emit AssetTransferred(from, to, tokenId, 0); // No payment made
emit ProviderFreeTransfer(tokenId, asset.provider, to);
// Return any sent ETH back to provider since no payment is needed
if (msg.value > 0) {
payable(msg.sender).transfer(msg.value);
}
return;
}
// For non-provider transfers, calculate all fees
uint256 providerFee = asset.transferValue;
uint256 platformFee = calculatePlatformFee(providerFee);
uint256 totalRequired = providerFee + platformFee;
require(
msg.value >= totalRequired,
"Insufficient payment for provider royalty and platform fee"
);
// Pay provider from user's sent ETH (only if transfer value > 0)
if (providerFee > 0) {
payable(asset.provider).transfer(providerFee);
}
// Pay platform fee to same recipient as minting fees (only if platform fee > 0)
if (platformFee > 0) {
payable(_platformFeeRecipient).transfer(platformFee);
emit PlatformFeePaid(tokenId, msg.sender, platformFee);
}
// Return excess ETH to sender if any
if (msg.value > totalRequired) {
payable(msg.sender).transfer(msg.value - totalRequired);
}
// Call the internal transfer function in MultiOwnerNFT
_transfer(from, to, tokenId);
emit AssetTransferred(from, to, tokenId, providerFee);
}
// Allow the contract to receive ETH to fund transfers
receive() external payable {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bool","name":"archived","type":"bool"}],"name":"ArchivedStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"bytes32","name":"fileHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"transferValue","type":"uint256"}],"name":"AssetProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"transferValue","type":"uint256"}],"name":"AssetTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBaseUpdateValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBaseUpdateValue","type":"uint256"}],"name":"BaseUpdateValueUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"MintingFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"MintingFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"PlatformFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"newRecipient","type":"address"}],"name":"PlatformFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"PlatformFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ProviderFreeTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"oldProvider","type":"address"},{"indexed":true,"internalType":"address","name":"newProvider","type":"address"}],"name":"ProviderTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"TokenMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"TokenTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldTransferValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTransferValue","type":"uint256"}],"name":"TransferValueUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"assetId","type":"uint256"},{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ownersCount","type":"uint256"}],"name":"UpdateValueFeePaid","type":"event"},{"inputs":[],"name":"MAX_PLATFORM_FEE_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"archive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"transferValue","type":"uint256"}],"name":"calculatePlatformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getAssetDetails","outputs":[{"components":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"string","name":"assetName","type":"string"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"bytes32","name":"fileHash","type":"bytes32"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"uint256","name":"transferValue","type":"uint256"}],"internalType":"struct IDigitalAsset.AssetDetails","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getAssetName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetsTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseUpdateValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMintingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getOwnersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformFeeConfiguration","outputs":[{"internalType":"uint256","name":"mintingFee","type":"uint256"},{"internalType":"uint256","name":"transferFeeRatio","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformFeeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"address","name":"caller","type":"address"}],"name":"getTransferCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"address","name":"caller","type":"address"}],"name":"getTransferCostBreakdown","outputs":[{"internalType":"uint256","name":"providerFee","type":"uint256"},{"internalType":"uint256","name":"platformFee","type":"uint256"},{"internalType":"uint256","name":"totalCost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"}],"name":"getUpdateValueCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"isArchived","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"address","name":"caller","type":"address"}],"name":"isTransferFreeForCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"assetName","type":"string"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"bytes32","name":"fileHash","type":"bytes32"},{"internalType":"uint256","name":"transferValue","type":"uint256"}],"name":"provide","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"newBaseUpdateValue","type":"uint256"}],"name":"setBaseUpdateValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setMintingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"setPlatformFeeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"setPlatformFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"uint256","name":"newTransferValue","type":"uint256"}],"name":"setTransferValue","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"smartTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFromWithPayment","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetId","type":"uint256"},{"internalType":"address","name":"newProvider","type":"address"}],"name":"transferProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608060405233805f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610076575f6040517f1e4fbdf700000000000000000000000000000000000000000000000000000000815260040161006d91906101ef565b60405180910390fd5b610085816100ef60201b60201c565b50503360095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060fa6008819055506601c6bf52634000600a819055506509184e72a000600b81905550610208565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6101d9826101b0565b9050919050565b6101e9816101cf565b82525050565b5f6020820190506102025f8301846101e0565b92915050565b614da5806102155f395ff3fe60806040526004361061025f575f3560e01c806374c5aed411610143578063b59d88a9116100b5578063e985e9c511610079578063e985e9c51461091c578063e9f061d414610958578063eaf2177b14610982578063f2fde38b146109be578063f70e663d146109e6578063f723acff14610a0e57610266565b8063b59d88a91461085c578063b88d4fde14610886578063bf7f8494146108ae578063ddf5db5b146108ca578063e7f1d082146108f257610266565b806393c829fc1161010757806393c829fc1461073c5780639ac8811e146107645780639c58951e146107a0578063a1f24b3d146107dc578063a22cb46514610818578063a7d060271461084057610266565b806374c5aed41461065a578063779fcc58146106845780637af02911146106ac5780638a42cef3146106e85780638da5cb5b1461071257610266565b806323b872dd116101dc5780635a5d096c116101a05780635a5d096c146105285780635c42d0791461056457806360ad29bd146105a05780636352211e146105cc57806370a0823114610608578063715018a61461064457610266565b806323b872dd1461045057806324fc099b146104785780634205f59d146104b457806342842e0e146104e457806343bd08be1461050c57610266565b806318160ddd1161022357806318160ddd146103825780631871e243146103ac5780631b8b8c34146103d45780632004ffd9146103fe578063238a47091461042857610266565b806301ffc9a71461026a578063081812fc146102a6578063095ea7b3146102e25780630cbab4f71461030a5780631062b39f1461034657610266565b3661026657005b5f5ffd5b348015610275575f5ffd5b50610290600480360381019061028b9190613328565b610a4c565b60405161029d919061336d565b60405180910390f35b3480156102b1575f5ffd5b506102cc60048036038101906102c791906133b9565b610ac5565b6040516102d99190613423565b60405180910390f35b3480156102ed575f5ffd5b5061030860048036038101906103039190613466565b610b01565b005b348015610315575f5ffd5b50610330600480360381019061032b91906133b9565b610b3c565b60405161033d91906134b3565b60405180910390f35b348015610351575f5ffd5b5061036c600480360381019061036791906133b9565b610b71565b60405161037991906134b3565b60405180910390f35b34801561038d575f5ffd5b50610396610bdc565b6040516103a391906134b3565b60405180910390f35b3480156103b7575f5ffd5b506103d260048036038101906103cd91906134cc565b610be5565b005b3480156103df575f5ffd5b506103e8610cfd565b6040516103f591906134b3565b60405180910390f35b348015610409575f5ffd5b50610412610d03565b60405161041f91906134b3565b60405180910390f35b348015610433575f5ffd5b5061044e600480360381019061044991906133b9565b610ded565b005b34801561045b575f5ffd5b50610476600480360381019061047191906134f7565b610e3f565b005b348015610483575f5ffd5b5061049e600480360381019061049991906133b9565b610f06565b6040516104ab91906135b7565b60405180910390f35b6104ce60048036038101906104c99190613736565b610ff2565b6040516104db91906134b3565b60405180910390f35b3480156104ef575f5ffd5b5061050a600480360381019061050591906134f7565b611299565b005b610526600480360381019061052191906134f7565b61139f565b005b348015610533575f5ffd5b5061054e600480360381019061054991906137b6565b611549565b60405161055b919061336d565b60405180910390f35b34801561056f575f5ffd5b5061058a600480360381019061058591906133b9565b6115bd565b6040516105979190613423565b60405180910390f35b3480156105ab575f5ffd5b506105b4611641565b6040516105c3939291906137f4565b60405180910390f35b3480156105d7575f5ffd5b506105f260048036038101906105ed91906133b9565b611677565b6040516105ff9190613423565b60405180910390f35b348015610613575f5ffd5b5061062e600480360381019061062991906134cc565b6116ea565b60405161063b91906134b3565b60405180910390f35b34801561064f575f5ffd5b5061065861179e565b005b348015610665575f5ffd5b5061066e6117b1565b60405161067b91906134b3565b60405180910390f35b34801561068f575f5ffd5b506106aa60048036038101906106a591906133b9565b6117bf565b005b3480156106b7575f5ffd5b506106d260048036038101906106cd91906137b6565b611811565b6040516106df919061336d565b60405180910390f35b3480156106f3575f5ffd5b506106fc611873565b60405161070991906134b3565b60405180910390f35b34801561071d575f5ffd5b5061072661187c565b6040516107339190613423565b60405180910390f35b348015610747575f5ffd5b50610762600480360381019061075d91906133b9565b6118a3565b005b34801561076f575f5ffd5b5061078a600480360381019061078591906133b9565b611a41565b60405161079791906134b3565b60405180910390f35b3480156107ab575f5ffd5b506107c660048036038101906107c191906137b6565b611aaa565b6040516107d3919061336d565b60405180910390f35b3480156107e7575f5ffd5b5061080260048036038101906107fd91906133b9565b611b70565b60405161080f9190613924565b60405180910390f35b348015610823575f5ffd5b5061083e6004803603810190610839919061396e565b611cdb565b005b61085a600480360381019061085591906134f7565b611d16565b005b348015610867575f5ffd5b50610870611ddd565b60405161087d91906134b3565b60405180910390f35b348015610891575f5ffd5b506108ac60048036038101906108a79190613a4a565b611de6565b005b6108c860048036038101906108c39190613aca565b611edf565b005b3480156108d5575f5ffd5b506108f060048036038101906108eb91906137b6565b612196565b005b3480156108fd575f5ffd5b5061090661244c565b60405161091391906134b3565b60405180910390f35b348015610927575f5ffd5b50610942600480360381019061093d9190613b08565b612455565b60405161094f919061336d565b60405180910390f35b348015610963575f5ffd5b5061096c612491565b6040516109799190613423565b60405180910390f35b34801561098d575f5ffd5b506109a860048036038101906109a391906137b6565b6124b9565b6040516109b591906134b3565b60405180910390f35b3480156109c9575f5ffd5b506109e460048036038101906109df91906134cc565b6125a1565b005b3480156109f1575f5ffd5b50610a0c6004803603810190610a0791906133b9565b612625565b005b348015610a19575f5ffd5b50610a346004803603810190610a2f91906137b6565b6126bc565b604051610a4393929190613b46565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610abe5750610abd826127a9565b5b9050919050565b5f6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af890613bc5565b60405180910390fd5b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3390613bc5565b60405180910390fd5b5f5f60085403610b4e575f9050610b6c565b61271060085483610b5f9190613c10565b610b699190613c7e565b90505b919050565b5f610b7b82612812565b610bba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb190613cf8565b60405180910390fd5b5f610bc483611a41565b905080600b54610bd49190613c10565b915050919050565b5f600154905090565b610bed612835565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610c5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5290613d86565b60405180910390fd5b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faf04973bb8004e313cfd09017b963bee1e6f6ffb9be88c07a0c5ce5fafe934038183604051610cf1929190613da4565b60405180910390a15050565b6103e881565b5f60015f815480929190610d1690613dcb565b9190505550610d47610d266128bc565b60025f60015481526020019081526020015f206128c390919063ffffffff16565b50600160055f610d556128bc565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610d9c9190613e12565b925050819055507f3a5398bda6f1f57d6c96834fa9bf02b5517bdc847d14312015a917ba421c31c9600154610dcf6128bc565b604051610ddd929190613e45565b60405180910390a1600154905090565b610df5612835565b5f600a54905081600a819055507fc24d648b8b29d6566f302551df9152ced5a44785e31f38d1d047c8168dd345198183604051610e33929190613e6c565b60405180910390a15050565b610e498133611549565b610e88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e7f90613f03565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ef6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eed90613f91565b60405180910390fd5b610f018383836128f0565b505050565b6060610f1182612812565b610f50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4790613cf8565b60405180910390fd5b60075f8381526020019081526020015f206001018054610f6f90613fdc565b80601f0160208091040260200160405190810160405280929190818152602001828054610f9b90613fdc565b8015610fe65780601f10610fbd57610100808354040283529160200191610fe6565b820191905f5260205f20905b815481529060010190602001808311610fc957829003601f168201915b50505050509050919050565b5f600a54341015611038576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102f90614056565b60405180910390fd5b5f600a5411156110aa5760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc600a5490811502906040515f60405180830381858888f193505050501580156110a8573d5f5f3e3d5ffd5b505b600a54341115611106573373ffffffffffffffffffffffffffffffffffffffff166108fc600a54346110dc9190614074565b90811502906040515f60405180830381858888f19350505050158015611104573d5f5f3e3d5ffd5b505b5f61110f610d03565b90506040518060c001604052808281526020018781526020018681526020018581526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018481525060075f8381526020019081526020015f205f820151815f015560208201518160010190816111829190614247565b5060408201518160020155606082015181600301556080820151816004015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a082015181600501559050503373ffffffffffffffffffffffffffffffffffffffff1685827fe01de5b29a6094ef6a36627c090f3cb632950fdb59e37c6822fabaf95797c7b88787604051611234929190614325565b60405180910390a43373ffffffffffffffffffffffffffffffffffffffff16817f393da669662f390b3a6231c718abd304b8860ddb7bec15aea0a5ed19f6a5a176600a5460405161128591906134b3565b60405180910390a380915050949350505050565b808360065f8381526020019081526020015f205f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615611334576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132b906143bc565b60405180910390fd5b61133f858585610e3f565b61135985858560405180602001604052805f815250612966565b611398576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161138f9061444a565b60405180910390fd5b5050505050565b6113a98133611549565b6113e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113df90613f03565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144d90613f91565b60405180910390fd5b60075f8281526020019081526020015f206004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806114d657505f60075f8381526020019081526020015f2060050154145b15611538576114e68383836128f0565b5f341115611533573373ffffffffffffffffffffffffffffffffffffffff166108fc3490811502906040515f60405180830381858888f19350505050158015611531573d5f5f3e3d5ffd5b505b611544565b611543838383612adb565b5b505050565b5f61155383612812565b611592576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611589906144b2565b60405180910390fd5b6115b58260025f8681526020019081526020015f20612eed90919063ffffffff16565b905092915050565b5f6115c782612812565b611606576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115fd90613cf8565b60405180910390fd5b60075f8381526020019081526020015f206004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f5f5f600a5460085460095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16925092509250909192565b5f61168182612812565b6116c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b790614540565b60405180910390fd5b6116e35f60025f8581526020019081526020015f20612f1a90919063ffffffff16565b9050919050565b5f5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611759576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611750906145ce565b60405180910390fd5b60055f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6117a6612835565b6117af5f612f31565b565b5f6117ba610bdc565b905090565b6117c7612835565b5f600b54905081600b819055507fb060c4ab17f0c7ed3fef6a624af782db0e2dda0ba4ed1527451a31c53ca35ccb8183604051611805929190613e6c565b60405180910390a15050565b5f60065f8481526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f600854905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6118ad8133611549565b6118ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118e39061465c565b60405180910390fd5b5f151560065f8381526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615151461198a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611981906146ea565b60405180910390fd5b600160065f8381526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff16817fa912af6e067545dfea05a1bbe5b356ddabd12ac4c18dce3835ab74e994ceca9c6001604051611a36919061336d565b60405180910390a350565b5f611a4b82612812565b611a8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a81906144b2565b60405180910390fd5b611aa360025f8481526020019081526020015f20612ff2565b9050919050565b5f611ab483612812565b611af3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aea90613cf8565b60405180910390fd5b5f60075f8581526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480611b6757505f8160050154145b91505092915050565b611b7861327b565b611b8182612812565b611bc0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb790613cf8565b60405180910390fd5b5f60075f8481526020019081526020015f2090506040518060c00160405280825f01548152602001826001018054611bf790613fdc565b80601f0160208091040260200160405190810160405280929190818152602001828054611c2390613fdc565b8015611c6e5780601f10611c4557610100808354040283529160200191611c6e565b820191905f5260205f20905b815481529060010190602001808311611c5157829003601f168201915b505050505081526020018260020154815260200182600301548152602001826004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018260050154815250915050919050565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0d90613bc5565b60405180910390fd5b611d208133611549565b611d5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d5690613f03565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611dcd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dc490613f91565b60405180910390fd5b611dd8838383612adb565b505050565b5f600a54905090565b818460065f8381526020019081526020015f205f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615611e81576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e78906143bc565b60405180910390fd5b611e8c868686610e3f565b611e9886868686612966565b611ed7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ece9061444a565b60405180910390fd5b505050505050565b611ee882612812565b611f27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f1e90613cf8565b60405180910390fd5b5f60075f8481526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611fcc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fc390614778565b60405180910390fd5b5f611fd684611a41565b90505f81600b54611fe79190613c10565b90508034101561202c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161202390614806565b60405180910390fd5b5f81111561209a5760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015612098573d5f5f3e3d5ffd5b505b803411156120f2573373ffffffffffffffffffffffffffffffffffffffff166108fc82346120c89190614074565b90811502906040515f60405180830381858888f193505050501580156120f0573d5f5f3e3d5ffd5b505b5f83600501549050848460050181905550857f7cb800311565ebb8eabf186c56a5c9903a855e84dee28a907c9dbb03b7f065b58287604051612135929190613e6c565b60405180910390a23373ffffffffffffffffffffffffffffffffffffffff16867f0100caa23996248b57af14d2e9979c27ec944b6092dc300483e42332541edbf18486604051612186929190613e6c565b60405180910390a3505050505050565b61219f82612812565b6121de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121d590613cf8565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361224c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161224390614894565b60405180910390fd5b5f60075f8481526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e890614922565b60405180910390fd5b806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612382576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612379906149b0565b60405180910390fd5b5f816004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082826004015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16857f63c5467be254a9fb4909a661a3860528283ba7526b2e51c72125f77dc36f04a260405160405180910390a450505050565b5f600b54905090565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161248890613bc5565b60405180910390fd5b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f6124c383612812565b612502576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124f990613cf8565b60405180910390fd5b5f60075f8581526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612575575f91505061259b565b5f816005015490505f61258782610b3c565b905080826125959190613e12565b93505050505b92915050565b6125a9612835565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612619575f6040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016126109190613423565b60405180910390fd5b61262281612f31565b50565b61262d612835565b6103e8811115612672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161266990614a18565b60405180910390fd5b5f6008549050816008819055507fd347e206f25a89b917fc9482f1a2d294d749baa4dc9bde7fb495ee11fe49164381836040516126b0929190613e6c565b60405180910390a15050565b5f5f5f6126c885612812565b612707576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126fe90613cf8565b60405180910390fd5b5f60075f8781526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612780575f5f5f935093509350506127a2565b8060050154935061279084610b3c565b9250828461279e9190613e12565b9150505b9250925092565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f5f61282d60025f8581526020019081526020015f20612ff2565b119050919050565b61283d6128bc565b73ffffffffffffffffffffffffffffffffffffffff1661285b61187c565b73ffffffffffffffffffffffffffffffffffffffff16146128ba5761287e6128bc565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016128b19190613423565b60405180910390fd5b565b5f33905090565b5f6128e8835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613005565b905092915050565b6128fb83838361306c565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f7a3278a8c40fdf2dcb3301c764c869a2d4514928f1b7c49671663b7a4e5b7ef05f6040516129599190614a6f565b60405180910390a4505050565b5f5f8473ffffffffffffffffffffffffffffffffffffffff163b0361298e5760019050612ad3565b8373ffffffffffffffffffffffffffffffffffffffff1663150b7a02338786866040518563ffffffff1660e01b81526004016129cd9493929190614ada565b6020604051808303815f875af1925050508015612a0857506040513d601f19601f82011682018060405250810190612a059190614b38565b60015b612a87573d805f8114612a36576040519150601f19603f3d011682016040523d82523d5f602084013e612a3b565b606091505b505f815103612a7f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a769061444a565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150505b949350505050565b5f60075f8381526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603612c8757612b5084848461306c565b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f7a3278a8c40fdf2dcb3301c764c869a2d4514928f1b7c49671663b7a4e5b7ef05f604051612bae9190614a6f565b60405180910390a48273ffffffffffffffffffffffffffffffffffffffff16816004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16837f0ae46aa46a96d1892b9ab9d26698af560946bc41ebe9f17f4c6dd67cdec4aa5360405160405180910390a45f341115612c81573373ffffffffffffffffffffffffffffffffffffffff166108fc3490811502906040515f60405180830381858888f19350505050158015612c7f573d5f5f3e3d5ffd5b505b50612ee8565b5f816005015490505f612c9982610b3c565b90505f8183612ca89190613e12565b905080341015612ced576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ce490614bd3565b60405180910390fd5b5f831115612d5d57836004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015612d5b573d5f5f3e3d5ffd5b505b5f821115612e1a5760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350505050158015612dc9573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff16857f0e61cfd0ee655641b3ed0a1dd373ec3cacf4c090de1f33708e3a4091f494766284604051612e1191906134b3565b60405180910390a35b80341115612e72573373ffffffffffffffffffffffffffffffffffffffff166108fc8234612e489190614074565b90811502906040515f60405180830381858888f19350505050158015612e70573d5f5f3e3d5ffd5b505b612e7d87878761306c565b848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f7a3278a8c40fdf2dcb3301c764c869a2d4514928f1b7c49671663b7a4e5b7ef086604051612edb91906134b3565b60405180910390a4505050505b505050565b5f612f12835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613225565b905092915050565b5f612f27835f0183613245565b5f1c905092915050565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f612ffe825f0161326c565b9050919050565b5f6130108383613225565b61306257825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050613066565b5f90505b92915050565b6130768184611549565b6130b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130ac90614c61565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613123576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161311a90613f91565b60405180910390fd5b61312d8183611549565b1561316d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161316490614cef565b60405180910390fd5b6131908260025f8481526020019081526020015f206128c390919063ffffffff16565b50600160055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546131de9190613e12565b925050819055507fa84f763be5bb36163517fb87c7af39f875a97866fdf7806eb1b3eac837ae35ea81848460405161321893929190614d0d565b60405180910390a1505050565b5f5f836001015f8481526020019081526020015f20541415905092915050565b5f825f01828154811061325b5761325a614d42565b5b905f5260205f200154905092915050565b5f815f01805490509050919050565b6040518060c001604052805f8152602001606081526020015f81526020015f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81525090565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613307816132d3565b8114613311575f5ffd5b50565b5f81359050613322816132fe565b92915050565b5f6020828403121561333d5761333c6132cb565b5b5f61334a84828501613314565b91505092915050565b5f8115159050919050565b61336781613353565b82525050565b5f6020820190506133805f83018461335e565b92915050565b5f819050919050565b61339881613386565b81146133a2575f5ffd5b50565b5f813590506133b38161338f565b92915050565b5f602082840312156133ce576133cd6132cb565b5b5f6133db848285016133a5565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61340d826133e4565b9050919050565b61341d81613403565b82525050565b5f6020820190506134365f830184613414565b92915050565b61344581613403565b811461344f575f5ffd5b50565b5f813590506134608161343c565b92915050565b5f5f6040838503121561347c5761347b6132cb565b5b5f61348985828601613452565b925050602061349a858286016133a5565b9150509250929050565b6134ad81613386565b82525050565b5f6020820190506134c65f8301846134a4565b92915050565b5f602082840312156134e1576134e06132cb565b5b5f6134ee84828501613452565b91505092915050565b5f5f5f6060848603121561350e5761350d6132cb565b5b5f61351b86828701613452565b935050602061352c86828701613452565b925050604061353d868287016133a5565b9150509250925092565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61358982613547565b6135938185613551565b93506135a3818560208601613561565b6135ac8161356f565b840191505092915050565b5f6020820190508181035f8301526135cf818461357f565b905092915050565b5f5ffd5b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6136158261356f565b810181811067ffffffffffffffff82111715613634576136336135df565b5b80604052505050565b5f6136466132c2565b9050613652828261360c565b919050565b5f67ffffffffffffffff821115613671576136706135df565b5b61367a8261356f565b9050602081019050919050565b828183375f83830152505050565b5f6136a76136a284613657565b61363d565b9050828152602081018484840111156136c3576136c26135db565b5b6136ce848285613687565b509392505050565b5f82601f8301126136ea576136e96135d7565b5b81356136fa848260208601613695565b91505092915050565b5f819050919050565b61371581613703565b811461371f575f5ffd5b50565b5f813590506137308161370c565b92915050565b5f5f5f5f6080858703121561374e5761374d6132cb565b5b5f85013567ffffffffffffffff81111561376b5761376a6132cf565b5b613777878288016136d6565b9450506020613788878288016133a5565b935050604061379987828801613722565b92505060606137aa878288016133a5565b91505092959194509250565b5f5f604083850312156137cc576137cb6132cb565b5b5f6137d9858286016133a5565b92505060206137ea85828601613452565b9150509250929050565b5f6060820190506138075f8301866134a4565b61381460208301856134a4565b6138216040830184613414565b949350505050565b61383281613386565b82525050565b5f82825260208201905092915050565b5f61385282613547565b61385c8185613838565b935061386c818560208601613561565b6138758161356f565b840191505092915050565b61388981613703565b82525050565b61389881613403565b82525050565b5f60c083015f8301516138b35f860182613829565b50602083015184820360208601526138cb8282613848565b91505060408301516138e06040860182613829565b5060608301516138f36060860182613880565b506080830151613906608086018261388f565b5060a083015161391960a0860182613829565b508091505092915050565b5f6020820190508181035f83015261393c818461389e565b905092915050565b61394d81613353565b8114613957575f5ffd5b50565b5f8135905061396881613944565b92915050565b5f5f60408385031215613984576139836132cb565b5b5f61399185828601613452565b92505060206139a28582860161395a565b9150509250929050565b5f67ffffffffffffffff8211156139c6576139c56135df565b5b6139cf8261356f565b9050602081019050919050565b5f6139ee6139e9846139ac565b61363d565b905082815260208101848484011115613a0a57613a096135db565b5b613a15848285613687565b509392505050565b5f82601f830112613a3157613a306135d7565b5b8135613a418482602086016139dc565b91505092915050565b5f5f5f5f60808587031215613a6257613a616132cb565b5b5f613a6f87828801613452565b9450506020613a8087828801613452565b9350506040613a91878288016133a5565b925050606085013567ffffffffffffffff811115613ab257613ab16132cf565b5b613abe87828801613a1d565b91505092959194509250565b5f5f60408385031215613ae057613adf6132cb565b5b5f613aed858286016133a5565b9250506020613afe858286016133a5565b9150509250929050565b5f5f60408385031215613b1e57613b1d6132cb565b5b5f613b2b85828601613452565b9250506020613b3c85828601613452565b9150509250929050565b5f606082019050613b595f8301866134a4565b613b6660208301856134a4565b613b7360408301846134a4565b949350505050565b7f4d4f2d4e46543a20617070726f76616c73206e6f7420737570706f72746564005f82015250565b5f613baf601f83613551565b9150613bba82613b7b565b602082019050919050565b5f6020820190508181035f830152613bdc81613ba3565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f613c1a82613386565b9150613c2583613386565b9250828202613c3381613386565b91508282048414831517613c4a57613c49613be3565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613c8882613386565b9150613c9383613386565b925082613ca357613ca2613c51565b5b828204905092915050565b7f41737365743a20417373657420646f6573206e6f7420657869737400000000005f82015250565b5f613ce2601b83613551565b9150613ced82613cae565b602082019050919050565b5f6020820190508181035f830152613d0f81613cd6565b9050919050565b7f506c6174666f726d2066656520726563697069656e742063616e6e6f742062655f8201527f207a65726f206164647265737300000000000000000000000000000000000000602082015250565b5f613d70602d83613551565b9150613d7b82613d16565b604082019050919050565b5f6020820190508181035f830152613d9d81613d64565b9050919050565b5f604082019050613db75f830185613414565b613dc46020830184613414565b9392505050565b5f613dd582613386565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613e0757613e06613be3565b5b600182019050919050565b5f613e1c82613386565b9150613e2783613386565b9250828201905080821115613e3f57613e3e613be3565b5b92915050565b5f604082019050613e585f8301856134a4565b613e656020830184613414565b9392505050565b5f604082019050613e7f5f8301856134a4565b613e8c60208301846134a4565b9392505050565b7f4d4f2d4e46543a205472616e736665722066726f6d20696e636f7272656374205f8201527f6163636f756e7400000000000000000000000000000000000000000000000000602082015250565b5f613eed602783613551565b9150613ef882613e93565b604082019050919050565b5f6020820190508181035f830152613f1a81613ee1565b9050919050565b7f4d4f2d4e46543a205472616e7366657220746f20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f613f7b602483613551565b9150613f8682613f21565b604082019050919050565b5f6020820190508181035f830152613fa881613f6f565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680613ff357607f821691505b60208210810361400657614005613faf565b5b50919050565b7f496e73756666696369656e74206d696e74696e672066656500000000000000005f82015250565b5f614040601883613551565b915061404b8261400c565b602082019050919050565b5f6020820190508181035f83015261406d81614034565b9050919050565b5f61407e82613386565b915061408983613386565b92508282039050818111156140a1576140a0613be3565b5b92915050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026141037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826140c8565b61410d86836140c8565b95508019841693508086168417925050509392505050565b5f819050919050565b5f61414861414361413e84613386565b614125565b613386565b9050919050565b5f819050919050565b6141618361412e565b61417561416d8261414f565b8484546140d4565b825550505050565b5f5f905090565b61418c61417d565b614197818484614158565b505050565b5b818110156141ba576141af5f82614184565b60018101905061419d565b5050565b601f8211156141ff576141d0816140a7565b6141d9846140b9565b810160208510156141e8578190505b6141fc6141f4856140b9565b83018261419c565b50505b505050565b5f82821c905092915050565b5f61421f5f1984600802614204565b1980831691505092915050565b5f6142378383614210565b9150826002028217905092915050565b61425082613547565b67ffffffffffffffff811115614269576142686135df565b5b6142738254613fdc565b61427e8282856141be565b5f60209050601f8311600181146142af575f841561429d578287015190505b6142a7858261422c565b86555061430e565b601f1984166142bd866140a7565b5f5b828110156142e4578489015182556001820191506020850194506020810190506142bf565b8683101561430157848901516142fd601f891682614210565b8355505b6001600288020188555050505b505050505050565b61431f81613703565b82525050565b5f6040820190506143385f830185614316565b61434560208301846134a4565b9392505050565b7f4d4f2d4e46543a204f776e65722773207472616e73666572206162696c6974795f8201527f20697320617263686976656420666f72207468697320746f6b656e0000000000602082015250565b5f6143a6603b83613551565b91506143b18261434c565b604082019050919050565b5f6020820190508181035f8301526143d38161439a565b9050919050565b7f4d4f2d4e46543a207472616e7366657220746f206e6f6e2045524337323152655f8201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b5f614434603283613551565b915061443f826143da565b604082019050919050565b5f6020820190508181035f83015261446181614428565b9050919050565b7f4d4f2d4e46543a20546f6b656e20646f6573206e6f74206578697374000000005f82015250565b5f61449c601c83613551565b91506144a782614468565b602082019050919050565b5f6020820190508181035f8301526144c981614490565b9050919050565b7f4d4f2d4e46543a204f776e657220717565727920666f72206e6f6e65786973745f8201527f656e7420746f6b656e0000000000000000000000000000000000000000000000602082015250565b5f61452a602983613551565b9150614535826144d0565b604082019050919050565b5f6020820190508181035f8301526145578161451e565b9050919050565b7f4d4f2d4e46543a2042616c616e636520717565727920666f7220746865207a655f8201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b5f6145b8602a83613551565b91506145c38261455e565b604082019050919050565b5f6020820190508181035f8301526145e5816145ac565b9050919050565b7f4d4f2d4e46543a2043616c6c6572206973206e6f7420746865206f776e6572205f8201527f6f66207468697320746f6b656e00000000000000000000000000000000000000602082015250565b5f614646602d83613551565b9150614651826145ec565b604082019050919050565b5f6020820190508181035f8301526146738161463a565b9050919050565b7f4d4f2d4e46543a20546f6b656e2063616e206f6e6c79206265206172636869765f8201527f6564206f6e636520666f7220616e206f776e6572000000000000000000000000602082015250565b5f6146d4603483613551565b91506146df8261467a565b604082019050919050565b5f6020820190508181035f830152614701816146c8565b9050919050565b7f4f6e6c792070726f76696465722063616e20757064617465207472616e7366655f8201527f722076616c756500000000000000000000000000000000000000000000000000602082015250565b5f614762602783613551565b915061476d82614708565b604082019050919050565b5f6020820190508181035f83015261478f81614756565b9050919050565b7f496e73756666696369656e742066656520666f72207472616e736665722076615f8201527f6c75652075706461746500000000000000000000000000000000000000000000602082015250565b5f6147f0602a83613551565b91506147fb82614796565b604082019050919050565b5f6020820190508181035f83015261481d816147e4565b9050919050565b7f41737365743a204e65772070726f76696465722063616e6e6f74206265207a655f8201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b5f61487e602a83613551565b915061488982614824565b604082019050919050565b5f6020820190508181035f8301526148ab81614872565b9050919050565b7f4f6e6c792063757272656e742070726f76696465722063616e207472616e73665f8201527f65722070726f766964657220726f6c6500000000000000000000000000000000602082015250565b5f61490c603083613551565b9150614917826148b2565b604082019050919050565b5f6020820190508181035f83015261493981614900565b9050919050565b7f41737365743a204e65772070726f7669646572206d75737420626520646966665f8201527f6572656e742066726f6d2063757272656e742070726f76696465720000000000602082015250565b5f61499a603b83613551565b91506149a582614940565b604082019050919050565b5f6020820190508181035f8301526149c78161498e565b9050919050565b7f506c6174666f726d2066656520726174696f20746f6f206869676800000000005f82015250565b5f614a02601b83613551565b9150614a0d826149ce565b602082019050919050565b5f6020820190508181035f830152614a2f816149f6565b9050919050565b5f819050919050565b5f614a59614a54614a4f84614a36565b614125565b613386565b9050919050565b614a6981614a3f565b82525050565b5f602082019050614a825f830184614a60565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f614aac82614a88565b614ab68185614a92565b9350614ac6818560208601613561565b614acf8161356f565b840191505092915050565b5f608082019050614aed5f830187613414565b614afa6020830186613414565b614b0760408301856134a4565b8181036060830152614b198184614aa2565b905095945050505050565b5f81519050614b32816132fe565b92915050565b5f60208284031215614b4d57614b4c6132cb565b5b5f614b5a84828501614b24565b91505092915050565b7f496e73756666696369656e74207061796d656e7420666f722070726f766964655f8201527f7220726f79616c747920616e6420706c6174666f726d20666565000000000000602082015250565b5f614bbd603a83613551565b9150614bc882614b63565b604082019050919050565b5f6020820190508181035f830152614bea81614bb1565b9050919050565b7f4d4f2d4e46543a205472616e736665722066726f6d20696e636f7272656374205f8201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b5f614c4b602583613551565b9150614c5682614bf1565b604082019050919050565b5f6020820190508181035f830152614c7881614c3f565b9050919050565b7f4d4f2d4e46543a20526563697069656e7420697320616c726561647920616e205f8201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b5f614cd9602583613551565b9150614ce482614c7f565b604082019050919050565b5f6020820190508181035f830152614d0681614ccd565b9050919050565b5f606082019050614d205f8301866134a4565b614d2d6020830185613414565b614d3a6040830184613414565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea2646970667358221220b098130c8be97c7dba16b56a2638cd42cb9f932ab3262f27155d40ad064ba4b264736f6c634300081e0033
Deployed Bytecode
0x60806040526004361061025f575f3560e01c806374c5aed411610143578063b59d88a9116100b5578063e985e9c511610079578063e985e9c51461091c578063e9f061d414610958578063eaf2177b14610982578063f2fde38b146109be578063f70e663d146109e6578063f723acff14610a0e57610266565b8063b59d88a91461085c578063b88d4fde14610886578063bf7f8494146108ae578063ddf5db5b146108ca578063e7f1d082146108f257610266565b806393c829fc1161010757806393c829fc1461073c5780639ac8811e146107645780639c58951e146107a0578063a1f24b3d146107dc578063a22cb46514610818578063a7d060271461084057610266565b806374c5aed41461065a578063779fcc58146106845780637af02911146106ac5780638a42cef3146106e85780638da5cb5b1461071257610266565b806323b872dd116101dc5780635a5d096c116101a05780635a5d096c146105285780635c42d0791461056457806360ad29bd146105a05780636352211e146105cc57806370a0823114610608578063715018a61461064457610266565b806323b872dd1461045057806324fc099b146104785780634205f59d146104b457806342842e0e146104e457806343bd08be1461050c57610266565b806318160ddd1161022357806318160ddd146103825780631871e243146103ac5780631b8b8c34146103d45780632004ffd9146103fe578063238a47091461042857610266565b806301ffc9a71461026a578063081812fc146102a6578063095ea7b3146102e25780630cbab4f71461030a5780631062b39f1461034657610266565b3661026657005b5f5ffd5b348015610275575f5ffd5b50610290600480360381019061028b9190613328565b610a4c565b60405161029d919061336d565b60405180910390f35b3480156102b1575f5ffd5b506102cc60048036038101906102c791906133b9565b610ac5565b6040516102d99190613423565b60405180910390f35b3480156102ed575f5ffd5b5061030860048036038101906103039190613466565b610b01565b005b348015610315575f5ffd5b50610330600480360381019061032b91906133b9565b610b3c565b60405161033d91906134b3565b60405180910390f35b348015610351575f5ffd5b5061036c600480360381019061036791906133b9565b610b71565b60405161037991906134b3565b60405180910390f35b34801561038d575f5ffd5b50610396610bdc565b6040516103a391906134b3565b60405180910390f35b3480156103b7575f5ffd5b506103d260048036038101906103cd91906134cc565b610be5565b005b3480156103df575f5ffd5b506103e8610cfd565b6040516103f591906134b3565b60405180910390f35b348015610409575f5ffd5b50610412610d03565b60405161041f91906134b3565b60405180910390f35b348015610433575f5ffd5b5061044e600480360381019061044991906133b9565b610ded565b005b34801561045b575f5ffd5b50610476600480360381019061047191906134f7565b610e3f565b005b348015610483575f5ffd5b5061049e600480360381019061049991906133b9565b610f06565b6040516104ab91906135b7565b60405180910390f35b6104ce60048036038101906104c99190613736565b610ff2565b6040516104db91906134b3565b60405180910390f35b3480156104ef575f5ffd5b5061050a600480360381019061050591906134f7565b611299565b005b610526600480360381019061052191906134f7565b61139f565b005b348015610533575f5ffd5b5061054e600480360381019061054991906137b6565b611549565b60405161055b919061336d565b60405180910390f35b34801561056f575f5ffd5b5061058a600480360381019061058591906133b9565b6115bd565b6040516105979190613423565b60405180910390f35b3480156105ab575f5ffd5b506105b4611641565b6040516105c3939291906137f4565b60405180910390f35b3480156105d7575f5ffd5b506105f260048036038101906105ed91906133b9565b611677565b6040516105ff9190613423565b60405180910390f35b348015610613575f5ffd5b5061062e600480360381019061062991906134cc565b6116ea565b60405161063b91906134b3565b60405180910390f35b34801561064f575f5ffd5b5061065861179e565b005b348015610665575f5ffd5b5061066e6117b1565b60405161067b91906134b3565b60405180910390f35b34801561068f575f5ffd5b506106aa60048036038101906106a591906133b9565b6117bf565b005b3480156106b7575f5ffd5b506106d260048036038101906106cd91906137b6565b611811565b6040516106df919061336d565b60405180910390f35b3480156106f3575f5ffd5b506106fc611873565b60405161070991906134b3565b60405180910390f35b34801561071d575f5ffd5b5061072661187c565b6040516107339190613423565b60405180910390f35b348015610747575f5ffd5b50610762600480360381019061075d91906133b9565b6118a3565b005b34801561076f575f5ffd5b5061078a600480360381019061078591906133b9565b611a41565b60405161079791906134b3565b60405180910390f35b3480156107ab575f5ffd5b506107c660048036038101906107c191906137b6565b611aaa565b6040516107d3919061336d565b60405180910390f35b3480156107e7575f5ffd5b5061080260048036038101906107fd91906133b9565b611b70565b60405161080f9190613924565b60405180910390f35b348015610823575f5ffd5b5061083e6004803603810190610839919061396e565b611cdb565b005b61085a600480360381019061085591906134f7565b611d16565b005b348015610867575f5ffd5b50610870611ddd565b60405161087d91906134b3565b60405180910390f35b348015610891575f5ffd5b506108ac60048036038101906108a79190613a4a565b611de6565b005b6108c860048036038101906108c39190613aca565b611edf565b005b3480156108d5575f5ffd5b506108f060048036038101906108eb91906137b6565b612196565b005b3480156108fd575f5ffd5b5061090661244c565b60405161091391906134b3565b60405180910390f35b348015610927575f5ffd5b50610942600480360381019061093d9190613b08565b612455565b60405161094f919061336d565b60405180910390f35b348015610963575f5ffd5b5061096c612491565b6040516109799190613423565b60405180910390f35b34801561098d575f5ffd5b506109a860048036038101906109a391906137b6565b6124b9565b6040516109b591906134b3565b60405180910390f35b3480156109c9575f5ffd5b506109e460048036038101906109df91906134cc565b6125a1565b005b3480156109f1575f5ffd5b50610a0c6004803603810190610a0791906133b9565b612625565b005b348015610a19575f5ffd5b50610a346004803603810190610a2f91906137b6565b6126bc565b604051610a4393929190613b46565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610abe5750610abd826127a9565b5b9050919050565b5f6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af890613bc5565b60405180910390fd5b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3390613bc5565b60405180910390fd5b5f5f60085403610b4e575f9050610b6c565b61271060085483610b5f9190613c10565b610b699190613c7e565b90505b919050565b5f610b7b82612812565b610bba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb190613cf8565b60405180910390fd5b5f610bc483611a41565b905080600b54610bd49190613c10565b915050919050565b5f600154905090565b610bed612835565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610c5b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5290613d86565b60405180910390fd5b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507faf04973bb8004e313cfd09017b963bee1e6f6ffb9be88c07a0c5ce5fafe934038183604051610cf1929190613da4565b60405180910390a15050565b6103e881565b5f60015f815480929190610d1690613dcb565b9190505550610d47610d266128bc565b60025f60015481526020019081526020015f206128c390919063ffffffff16565b50600160055f610d556128bc565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610d9c9190613e12565b925050819055507f3a5398bda6f1f57d6c96834fa9bf02b5517bdc847d14312015a917ba421c31c9600154610dcf6128bc565b604051610ddd929190613e45565b60405180910390a1600154905090565b610df5612835565b5f600a54905081600a819055507fc24d648b8b29d6566f302551df9152ced5a44785e31f38d1d047c8168dd345198183604051610e33929190613e6c565b60405180910390a15050565b610e498133611549565b610e88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e7f90613f03565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ef6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eed90613f91565b60405180910390fd5b610f018383836128f0565b505050565b6060610f1182612812565b610f50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4790613cf8565b60405180910390fd5b60075f8381526020019081526020015f206001018054610f6f90613fdc565b80601f0160208091040260200160405190810160405280929190818152602001828054610f9b90613fdc565b8015610fe65780601f10610fbd57610100808354040283529160200191610fe6565b820191905f5260205f20905b815481529060010190602001808311610fc957829003601f168201915b50505050509050919050565b5f600a54341015611038576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161102f90614056565b60405180910390fd5b5f600a5411156110aa5760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc600a5490811502906040515f60405180830381858888f193505050501580156110a8573d5f5f3e3d5ffd5b505b600a54341115611106573373ffffffffffffffffffffffffffffffffffffffff166108fc600a54346110dc9190614074565b90811502906040515f60405180830381858888f19350505050158015611104573d5f5f3e3d5ffd5b505b5f61110f610d03565b90506040518060c001604052808281526020018781526020018681526020018581526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018481525060075f8381526020019081526020015f205f820151815f015560208201518160010190816111829190614247565b5060408201518160020155606082015181600301556080820151816004015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a082015181600501559050503373ffffffffffffffffffffffffffffffffffffffff1685827fe01de5b29a6094ef6a36627c090f3cb632950fdb59e37c6822fabaf95797c7b88787604051611234929190614325565b60405180910390a43373ffffffffffffffffffffffffffffffffffffffff16817f393da669662f390b3a6231c718abd304b8860ddb7bec15aea0a5ed19f6a5a176600a5460405161128591906134b3565b60405180910390a380915050949350505050565b808360065f8381526020019081526020015f205f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615611334576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161132b906143bc565b60405180910390fd5b61133f858585610e3f565b61135985858560405180602001604052805f815250612966565b611398576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161138f9061444a565b60405180910390fd5b5050505050565b6113a98133611549565b6113e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113df90613f03565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144d90613f91565b60405180910390fd5b60075f8281526020019081526020015f206004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806114d657505f60075f8381526020019081526020015f2060050154145b15611538576114e68383836128f0565b5f341115611533573373ffffffffffffffffffffffffffffffffffffffff166108fc3490811502906040515f60405180830381858888f19350505050158015611531573d5f5f3e3d5ffd5b505b611544565b611543838383612adb565b5b505050565b5f61155383612812565b611592576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611589906144b2565b60405180910390fd5b6115b58260025f8681526020019081526020015f20612eed90919063ffffffff16565b905092915050565b5f6115c782612812565b611606576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115fd90613cf8565b60405180910390fd5b60075f8381526020019081526020015f206004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f5f5f600a5460085460095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16925092509250909192565b5f61168182612812565b6116c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b790614540565b60405180910390fd5b6116e35f60025f8581526020019081526020015f20612f1a90919063ffffffff16565b9050919050565b5f5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611759576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611750906145ce565b60405180910390fd5b60055f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6117a6612835565b6117af5f612f31565b565b5f6117ba610bdc565b905090565b6117c7612835565b5f600b54905081600b819055507fb060c4ab17f0c7ed3fef6a624af782db0e2dda0ba4ed1527451a31c53ca35ccb8183604051611805929190613e6c565b60405180910390a15050565b5f60065f8481526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f600854905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6118ad8133611549565b6118ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118e39061465c565b60405180910390fd5b5f151560065f8381526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615151461198a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611981906146ea565b60405180910390fd5b600160065f8381526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff16817fa912af6e067545dfea05a1bbe5b356ddabd12ac4c18dce3835ab74e994ceca9c6001604051611a36919061336d565b60405180910390a350565b5f611a4b82612812565b611a8a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a81906144b2565b60405180910390fd5b611aa360025f8481526020019081526020015f20612ff2565b9050919050565b5f611ab483612812565b611af3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aea90613cf8565b60405180910390fd5b5f60075f8581526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480611b6757505f8160050154145b91505092915050565b611b7861327b565b611b8182612812565b611bc0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb790613cf8565b60405180910390fd5b5f60075f8481526020019081526020015f2090506040518060c00160405280825f01548152602001826001018054611bf790613fdc565b80601f0160208091040260200160405190810160405280929190818152602001828054611c2390613fdc565b8015611c6e5780601f10611c4557610100808354040283529160200191611c6e565b820191905f5260205f20905b815481529060010190602001808311611c5157829003601f168201915b505050505081526020018260020154815260200182600301548152602001826004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018260050154815250915050919050565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d0d90613bc5565b60405180910390fd5b611d208133611549565b611d5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d5690613f03565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611dcd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dc490613f91565b60405180910390fd5b611dd8838383612adb565b505050565b5f600a54905090565b818460065f8381526020019081526020015f205f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615611e81576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e78906143bc565b60405180910390fd5b611e8c868686610e3f565b611e9886868686612966565b611ed7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ece9061444a565b60405180910390fd5b505050505050565b611ee882612812565b611f27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f1e90613cf8565b60405180910390fd5b5f60075f8481526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611fcc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fc390614778565b60405180910390fd5b5f611fd684611a41565b90505f81600b54611fe79190613c10565b90508034101561202c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161202390614806565b60405180910390fd5b5f81111561209a5760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015612098573d5f5f3e3d5ffd5b505b803411156120f2573373ffffffffffffffffffffffffffffffffffffffff166108fc82346120c89190614074565b90811502906040515f60405180830381858888f193505050501580156120f0573d5f5f3e3d5ffd5b505b5f83600501549050848460050181905550857f7cb800311565ebb8eabf186c56a5c9903a855e84dee28a907c9dbb03b7f065b58287604051612135929190613e6c565b60405180910390a23373ffffffffffffffffffffffffffffffffffffffff16867f0100caa23996248b57af14d2e9979c27ec944b6092dc300483e42332541edbf18486604051612186929190613e6c565b60405180910390a3505050505050565b61219f82612812565b6121de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121d590613cf8565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361224c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161224390614894565b60405180910390fd5b5f60075f8481526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e890614922565b60405180910390fd5b806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612382576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612379906149b0565b60405180910390fd5b5f816004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082826004015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16857f63c5467be254a9fb4909a661a3860528283ba7526b2e51c72125f77dc36f04a260405160405180910390a450505050565b5f600b54905090565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161248890613bc5565b60405180910390fd5b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f6124c383612812565b612502576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124f990613cf8565b60405180910390fd5b5f60075f8581526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612575575f91505061259b565b5f816005015490505f61258782610b3c565b905080826125959190613e12565b93505050505b92915050565b6125a9612835565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612619575f6040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016126109190613423565b60405180910390fd5b61262281612f31565b50565b61262d612835565b6103e8811115612672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161266990614a18565b60405180910390fd5b5f6008549050816008819055507fd347e206f25a89b917fc9482f1a2d294d749baa4dc9bde7fb495ee11fe49164381836040516126b0929190613e6c565b60405180910390a15050565b5f5f5f6126c885612812565b612707576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126fe90613cf8565b60405180910390fd5b5f60075f8781526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612780575f5f5f935093509350506127a2565b8060050154935061279084610b3c565b9250828461279e9190613e12565b9150505b9250925092565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f5f61282d60025f8581526020019081526020015f20612ff2565b119050919050565b61283d6128bc565b73ffffffffffffffffffffffffffffffffffffffff1661285b61187c565b73ffffffffffffffffffffffffffffffffffffffff16146128ba5761287e6128bc565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016128b19190613423565b60405180910390fd5b565b5f33905090565b5f6128e8835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613005565b905092915050565b6128fb83838361306c565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f7a3278a8c40fdf2dcb3301c764c869a2d4514928f1b7c49671663b7a4e5b7ef05f6040516129599190614a6f565b60405180910390a4505050565b5f5f8473ffffffffffffffffffffffffffffffffffffffff163b0361298e5760019050612ad3565b8373ffffffffffffffffffffffffffffffffffffffff1663150b7a02338786866040518563ffffffff1660e01b81526004016129cd9493929190614ada565b6020604051808303815f875af1925050508015612a0857506040513d601f19601f82011682018060405250810190612a059190614b38565b60015b612a87573d805f8114612a36576040519150601f19603f3d011682016040523d82523d5f602084013e612a3b565b606091505b505f815103612a7f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a769061444a565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150505b949350505050565b5f60075f8381526020019081526020015f209050806004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603612c8757612b5084848461306c565b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f7a3278a8c40fdf2dcb3301c764c869a2d4514928f1b7c49671663b7a4e5b7ef05f604051612bae9190614a6f565b60405180910390a48273ffffffffffffffffffffffffffffffffffffffff16816004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16837f0ae46aa46a96d1892b9ab9d26698af560946bc41ebe9f17f4c6dd67cdec4aa5360405160405180910390a45f341115612c81573373ffffffffffffffffffffffffffffffffffffffff166108fc3490811502906040515f60405180830381858888f19350505050158015612c7f573d5f5f3e3d5ffd5b505b50612ee8565b5f816005015490505f612c9982610b3c565b90505f8183612ca89190613e12565b905080341015612ced576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ce490614bd3565b60405180910390fd5b5f831115612d5d57836004015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015612d5b573d5f5f3e3d5ffd5b505b5f821115612e1a5760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350505050158015612dc9573d5f5f3e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff16857f0e61cfd0ee655641b3ed0a1dd373ec3cacf4c090de1f33708e3a4091f494766284604051612e1191906134b3565b60405180910390a35b80341115612e72573373ffffffffffffffffffffffffffffffffffffffff166108fc8234612e489190614074565b90811502906040515f60405180830381858888f19350505050158015612e70573d5f5f3e3d5ffd5b505b612e7d87878761306c565b848673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f7a3278a8c40fdf2dcb3301c764c869a2d4514928f1b7c49671663b7a4e5b7ef086604051612edb91906134b3565b60405180910390a4505050505b505050565b5f612f12835f018373ffffffffffffffffffffffffffffffffffffffff165f1b613225565b905092915050565b5f612f27835f0183613245565b5f1c905092915050565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f612ffe825f0161326c565b9050919050565b5f6130108383613225565b61306257825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050613066565b5f90505b92915050565b6130768184611549565b6130b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130ac90614c61565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613123576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161311a90613f91565b60405180910390fd5b61312d8183611549565b1561316d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161316490614cef565b60405180910390fd5b6131908260025f8481526020019081526020015f206128c390919063ffffffff16565b50600160055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546131de9190613e12565b925050819055507fa84f763be5bb36163517fb87c7af39f875a97866fdf7806eb1b3eac837ae35ea81848460405161321893929190614d0d565b60405180910390a1505050565b5f5f836001015f8481526020019081526020015f20541415905092915050565b5f825f01828154811061325b5761325a614d42565b5b905f5260205f200154905092915050565b5f815f01805490509050919050565b6040518060c001604052805f8152602001606081526020015f81526020015f81526020015f73ffffffffffffffffffffffffffffffffffffffff1681526020015f81525090565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613307816132d3565b8114613311575f5ffd5b50565b5f81359050613322816132fe565b92915050565b5f6020828403121561333d5761333c6132cb565b5b5f61334a84828501613314565b91505092915050565b5f8115159050919050565b61336781613353565b82525050565b5f6020820190506133805f83018461335e565b92915050565b5f819050919050565b61339881613386565b81146133a2575f5ffd5b50565b5f813590506133b38161338f565b92915050565b5f602082840312156133ce576133cd6132cb565b5b5f6133db848285016133a5565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61340d826133e4565b9050919050565b61341d81613403565b82525050565b5f6020820190506134365f830184613414565b92915050565b61344581613403565b811461344f575f5ffd5b50565b5f813590506134608161343c565b92915050565b5f5f6040838503121561347c5761347b6132cb565b5b5f61348985828601613452565b925050602061349a858286016133a5565b9150509250929050565b6134ad81613386565b82525050565b5f6020820190506134c65f8301846134a4565b92915050565b5f602082840312156134e1576134e06132cb565b5b5f6134ee84828501613452565b91505092915050565b5f5f5f6060848603121561350e5761350d6132cb565b5b5f61351b86828701613452565b935050602061352c86828701613452565b925050604061353d868287016133a5565b9150509250925092565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61358982613547565b6135938185613551565b93506135a3818560208601613561565b6135ac8161356f565b840191505092915050565b5f6020820190508181035f8301526135cf818461357f565b905092915050565b5f5ffd5b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6136158261356f565b810181811067ffffffffffffffff82111715613634576136336135df565b5b80604052505050565b5f6136466132c2565b9050613652828261360c565b919050565b5f67ffffffffffffffff821115613671576136706135df565b5b61367a8261356f565b9050602081019050919050565b828183375f83830152505050565b5f6136a76136a284613657565b61363d565b9050828152602081018484840111156136c3576136c26135db565b5b6136ce848285613687565b509392505050565b5f82601f8301126136ea576136e96135d7565b5b81356136fa848260208601613695565b91505092915050565b5f819050919050565b61371581613703565b811461371f575f5ffd5b50565b5f813590506137308161370c565b92915050565b5f5f5f5f6080858703121561374e5761374d6132cb565b5b5f85013567ffffffffffffffff81111561376b5761376a6132cf565b5b613777878288016136d6565b9450506020613788878288016133a5565b935050604061379987828801613722565b92505060606137aa878288016133a5565b91505092959194509250565b5f5f604083850312156137cc576137cb6132cb565b5b5f6137d9858286016133a5565b92505060206137ea85828601613452565b9150509250929050565b5f6060820190506138075f8301866134a4565b61381460208301856134a4565b6138216040830184613414565b949350505050565b61383281613386565b82525050565b5f82825260208201905092915050565b5f61385282613547565b61385c8185613838565b935061386c818560208601613561565b6138758161356f565b840191505092915050565b61388981613703565b82525050565b61389881613403565b82525050565b5f60c083015f8301516138b35f860182613829565b50602083015184820360208601526138cb8282613848565b91505060408301516138e06040860182613829565b5060608301516138f36060860182613880565b506080830151613906608086018261388f565b5060a083015161391960a0860182613829565b508091505092915050565b5f6020820190508181035f83015261393c818461389e565b905092915050565b61394d81613353565b8114613957575f5ffd5b50565b5f8135905061396881613944565b92915050565b5f5f60408385031215613984576139836132cb565b5b5f61399185828601613452565b92505060206139a28582860161395a565b9150509250929050565b5f67ffffffffffffffff8211156139c6576139c56135df565b5b6139cf8261356f565b9050602081019050919050565b5f6139ee6139e9846139ac565b61363d565b905082815260208101848484011115613a0a57613a096135db565b5b613a15848285613687565b509392505050565b5f82601f830112613a3157613a306135d7565b5b8135613a418482602086016139dc565b91505092915050565b5f5f5f5f60808587031215613a6257613a616132cb565b5b5f613a6f87828801613452565b9450506020613a8087828801613452565b9350506040613a91878288016133a5565b925050606085013567ffffffffffffffff811115613ab257613ab16132cf565b5b613abe87828801613a1d565b91505092959194509250565b5f5f60408385031215613ae057613adf6132cb565b5b5f613aed858286016133a5565b9250506020613afe858286016133a5565b9150509250929050565b5f5f60408385031215613b1e57613b1d6132cb565b5b5f613b2b85828601613452565b9250506020613b3c85828601613452565b9150509250929050565b5f606082019050613b595f8301866134a4565b613b6660208301856134a4565b613b7360408301846134a4565b949350505050565b7f4d4f2d4e46543a20617070726f76616c73206e6f7420737570706f72746564005f82015250565b5f613baf601f83613551565b9150613bba82613b7b565b602082019050919050565b5f6020820190508181035f830152613bdc81613ba3565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f613c1a82613386565b9150613c2583613386565b9250828202613c3381613386565b91508282048414831517613c4a57613c49613be3565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f613c8882613386565b9150613c9383613386565b925082613ca357613ca2613c51565b5b828204905092915050565b7f41737365743a20417373657420646f6573206e6f7420657869737400000000005f82015250565b5f613ce2601b83613551565b9150613ced82613cae565b602082019050919050565b5f6020820190508181035f830152613d0f81613cd6565b9050919050565b7f506c6174666f726d2066656520726563697069656e742063616e6e6f742062655f8201527f207a65726f206164647265737300000000000000000000000000000000000000602082015250565b5f613d70602d83613551565b9150613d7b82613d16565b604082019050919050565b5f6020820190508181035f830152613d9d81613d64565b9050919050565b5f604082019050613db75f830185613414565b613dc46020830184613414565b9392505050565b5f613dd582613386565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613e0757613e06613be3565b5b600182019050919050565b5f613e1c82613386565b9150613e2783613386565b9250828201905080821115613e3f57613e3e613be3565b5b92915050565b5f604082019050613e585f8301856134a4565b613e656020830184613414565b9392505050565b5f604082019050613e7f5f8301856134a4565b613e8c60208301846134a4565b9392505050565b7f4d4f2d4e46543a205472616e736665722066726f6d20696e636f7272656374205f8201527f6163636f756e7400000000000000000000000000000000000000000000000000602082015250565b5f613eed602783613551565b9150613ef882613e93565b604082019050919050565b5f6020820190508181035f830152613f1a81613ee1565b9050919050565b7f4d4f2d4e46543a205472616e7366657220746f20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f613f7b602483613551565b9150613f8682613f21565b604082019050919050565b5f6020820190508181035f830152613fa881613f6f565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680613ff357607f821691505b60208210810361400657614005613faf565b5b50919050565b7f496e73756666696369656e74206d696e74696e672066656500000000000000005f82015250565b5f614040601883613551565b915061404b8261400c565b602082019050919050565b5f6020820190508181035f83015261406d81614034565b9050919050565b5f61407e82613386565b915061408983613386565b92508282039050818111156140a1576140a0613be3565b5b92915050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026141037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826140c8565b61410d86836140c8565b95508019841693508086168417925050509392505050565b5f819050919050565b5f61414861414361413e84613386565b614125565b613386565b9050919050565b5f819050919050565b6141618361412e565b61417561416d8261414f565b8484546140d4565b825550505050565b5f5f905090565b61418c61417d565b614197818484614158565b505050565b5b818110156141ba576141af5f82614184565b60018101905061419d565b5050565b601f8211156141ff576141d0816140a7565b6141d9846140b9565b810160208510156141e8578190505b6141fc6141f4856140b9565b83018261419c565b50505b505050565b5f82821c905092915050565b5f61421f5f1984600802614204565b1980831691505092915050565b5f6142378383614210565b9150826002028217905092915050565b61425082613547565b67ffffffffffffffff811115614269576142686135df565b5b6142738254613fdc565b61427e8282856141be565b5f60209050601f8311600181146142af575f841561429d578287015190505b6142a7858261422c565b86555061430e565b601f1984166142bd866140a7565b5f5b828110156142e4578489015182556001820191506020850194506020810190506142bf565b8683101561430157848901516142fd601f891682614210565b8355505b6001600288020188555050505b505050505050565b61431f81613703565b82525050565b5f6040820190506143385f830185614316565b61434560208301846134a4565b9392505050565b7f4d4f2d4e46543a204f776e65722773207472616e73666572206162696c6974795f8201527f20697320617263686976656420666f72207468697320746f6b656e0000000000602082015250565b5f6143a6603b83613551565b91506143b18261434c565b604082019050919050565b5f6020820190508181035f8301526143d38161439a565b9050919050565b7f4d4f2d4e46543a207472616e7366657220746f206e6f6e2045524337323152655f8201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b5f614434603283613551565b915061443f826143da565b604082019050919050565b5f6020820190508181035f83015261446181614428565b9050919050565b7f4d4f2d4e46543a20546f6b656e20646f6573206e6f74206578697374000000005f82015250565b5f61449c601c83613551565b91506144a782614468565b602082019050919050565b5f6020820190508181035f8301526144c981614490565b9050919050565b7f4d4f2d4e46543a204f776e657220717565727920666f72206e6f6e65786973745f8201527f656e7420746f6b656e0000000000000000000000000000000000000000000000602082015250565b5f61452a602983613551565b9150614535826144d0565b604082019050919050565b5f6020820190508181035f8301526145578161451e565b9050919050565b7f4d4f2d4e46543a2042616c616e636520717565727920666f7220746865207a655f8201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b5f6145b8602a83613551565b91506145c38261455e565b604082019050919050565b5f6020820190508181035f8301526145e5816145ac565b9050919050565b7f4d4f2d4e46543a2043616c6c6572206973206e6f7420746865206f776e6572205f8201527f6f66207468697320746f6b656e00000000000000000000000000000000000000602082015250565b5f614646602d83613551565b9150614651826145ec565b604082019050919050565b5f6020820190508181035f8301526146738161463a565b9050919050565b7f4d4f2d4e46543a20546f6b656e2063616e206f6e6c79206265206172636869765f8201527f6564206f6e636520666f7220616e206f776e6572000000000000000000000000602082015250565b5f6146d4603483613551565b91506146df8261467a565b604082019050919050565b5f6020820190508181035f830152614701816146c8565b9050919050565b7f4f6e6c792070726f76696465722063616e20757064617465207472616e7366655f8201527f722076616c756500000000000000000000000000000000000000000000000000602082015250565b5f614762602783613551565b915061476d82614708565b604082019050919050565b5f6020820190508181035f83015261478f81614756565b9050919050565b7f496e73756666696369656e742066656520666f72207472616e736665722076615f8201527f6c75652075706461746500000000000000000000000000000000000000000000602082015250565b5f6147f0602a83613551565b91506147fb82614796565b604082019050919050565b5f6020820190508181035f83015261481d816147e4565b9050919050565b7f41737365743a204e65772070726f76696465722063616e6e6f74206265207a655f8201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b5f61487e602a83613551565b915061488982614824565b604082019050919050565b5f6020820190508181035f8301526148ab81614872565b9050919050565b7f4f6e6c792063757272656e742070726f76696465722063616e207472616e73665f8201527f65722070726f766964657220726f6c6500000000000000000000000000000000602082015250565b5f61490c603083613551565b9150614917826148b2565b604082019050919050565b5f6020820190508181035f83015261493981614900565b9050919050565b7f41737365743a204e65772070726f7669646572206d75737420626520646966665f8201527f6572656e742066726f6d2063757272656e742070726f76696465720000000000602082015250565b5f61499a603b83613551565b91506149a582614940565b604082019050919050565b5f6020820190508181035f8301526149c78161498e565b9050919050565b7f506c6174666f726d2066656520726174696f20746f6f206869676800000000005f82015250565b5f614a02601b83613551565b9150614a0d826149ce565b602082019050919050565b5f6020820190508181035f830152614a2f816149f6565b9050919050565b5f819050919050565b5f614a59614a54614a4f84614a36565b614125565b613386565b9050919050565b614a6981614a3f565b82525050565b5f602082019050614a825f830184614a60565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f614aac82614a88565b614ab68185614a92565b9350614ac6818560208601613561565b614acf8161356f565b840191505092915050565b5f608082019050614aed5f830187613414565b614afa6020830186613414565b614b0760408301856134a4565b8181036060830152614b198184614aa2565b905095945050505050565b5f81519050614b32816132fe565b92915050565b5f60208284031215614b4d57614b4c6132cb565b5b5f614b5a84828501614b24565b91505092915050565b7f496e73756666696369656e74207061796d656e7420666f722070726f766964655f8201527f7220726f79616c747920616e6420706c6174666f726d20666565000000000000602082015250565b5f614bbd603a83613551565b9150614bc882614b63565b604082019050919050565b5f6020820190508181035f830152614bea81614bb1565b9050919050565b7f4d4f2d4e46543a205472616e736665722066726f6d20696e636f7272656374205f8201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b5f614c4b602583613551565b9150614c5682614bf1565b604082019050919050565b5f6020820190508181035f830152614c7881614c3f565b9050919050565b7f4d4f2d4e46543a20526563697069656e7420697320616c726561647920616e205f8201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b5f614cd9602583613551565b9150614ce482614c7f565b604082019050919050565b5f6020820190508181035f830152614d0681614ccd565b9050919050565b5f606082019050614d205f8301866134a4565b614d2d6020830185613414565b614d3a6040830184613414565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea2646970667358221220b098130c8be97c7dba16b56a2638cd42cb9f932ab3262f27155d40ad064ba4b264736f6c634300081e0033
Deployed Bytecode Sourcemap
145317:16297:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;142716:256;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;138525:159;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;138192:139;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;155177:227;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;154337:266;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;136843:91;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;153023:370;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;146007:53;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;136000:372;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;153637:195;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;157199:481;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;148281:219;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;149146:1238;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;139307:495;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;158274:928;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;136380:301;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;152445:188;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;154926:243;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;137273:332;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;136942:323;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;9360:103;;;;;;;;;;;;;:::i;:::-;;148163:110;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;153942:275;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;137989:163;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;153401:106;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;8685:87;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;142190:518;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;137613:267;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;155469:413;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;148508:562;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;138339:178;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;157748:437;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;153840:94;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;139810:527;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;150392:1259;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;151659:778;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;154225:104;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;138692:192;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;153515:114;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;155966:560;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;9618:220;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;152696:319;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;156583:608;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;142716:256;142834:4;142886:25;142871:40;;;:11;:40;;;;:93;;;;142928:36;142952:11;142928:23;:36::i;:::-;142871:93;142851:113;;142716:256;;;:::o;138525:159::-;138615:7;138635:41;;;;;;;;;;:::i;:::-;;;;;;;;138192:139;138282:41;;;;;;;;;;:::i;:::-;;;;;;;;155177:227;155251:7;155296:1;155275:17;;:22;155271:36;;155306:1;155299:8;;;;155271:36;155363:5;155342:17;;155326:13;:33;;;;:::i;:::-;155325:43;;;;:::i;:::-;155318:50;;155177:227;;;;:::o;154337:266::-;154405:7;154433:16;154441:7;154433;:16::i;:::-;154425:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;154502:19;154524:23;154539:7;154524:14;:23::i;:::-;154502:45;;154584:11;154565:16;;:30;;;;:::i;:::-;154558:37;;;154337:266;;;:::o;136843:91::-;136887:7;136914:12;;136907:19;;136843:91;:::o;153023:370::-;8571:13;:11;:13::i;:::-;153140:1:::1;153116:26;;:12;:26;;::::0;153108:84:::1;;;;;;;;;;;;:::i;:::-;;;;;;;;;153213:20;153236:21;;;;;;;;;;;153213:44;;153292:12;153268:21;;:36;;;;;;;;;;;;;;;;;;153330:55;153358:12;153372;153330:55;;;;;;;:::i;:::-;;;;;;;;153097:296;153023:370:::0;:::o;146007:53::-;146056:4;146007:53;:::o;136000:372::-;136037:7;136057:12;;:14;;;;;;;;;:::i;:::-;;;;;;136150:39;136176:12;:10;:12::i;:::-;136150:7;:21;136158:12;;136150:21;;;;;;;;;;;:25;;:39;;;;:::i;:::-;;136276:1;136249:9;:23;136259:12;:10;:12::i;:::-;136249:23;;;;;;;;;;;;;;;;:28;;;;;;;:::i;:::-;;;;;;;;136295:39;136307:12;;136321;:10;:12::i;:::-;136295:39;;;;;;;:::i;:::-;;;;;;;;136352:12;;136345:19;;136000:372;:::o;153637:195::-;8571:13;:11;:13::i;:::-;153706:14:::1;153723:11;;153706:28;;153759:6;153745:11;:20;;;;153791:33;153809:6;153817;153791:33;;;;;;;:::i;:::-;;;;;;;;153695:137;153637:195:::0;:::o;157199:481::-;157347:28;157355:7;157364:10;157347:7;:28::i;:::-;157325:157;;;;;;;;;;;;:::i;:::-;;;;;;;;;157515:1;157501:16;;:2;:16;;;157493:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;157630:42;157654:4;157660:2;157664:7;157630:23;:42::i;:::-;157199:481;;;:::o;148281:219::-;148366:13;148400:16;148408:7;148400;:16::i;:::-;148392:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;148466:7;:16;148474:7;148466:16;;;;;;;;;;;:26;;148459:33;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;148281:219;;;:::o;149146:1238::-;149312:7;149393:11;;149380:9;:24;;149372:61;;;;;;;;;;;;:::i;:::-;;;;;;;;;149554:1;149540:11;;:15;149536:100;;;149580:21;;;;;;;;;;;149572:39;;:52;149612:11;;149572:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149536:100;149719:11;;149707:9;:23;149703:109;;;149755:10;149747:28;;:53;149788:11;;149776:9;:23;;;;:::i;:::-;149747:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149703:109;149882:15;149900:11;:9;:11::i;:::-;149882:29;;149941:255;;;;;;;;149980:7;149941:255;;;;150013:9;149941:255;;;;150043:4;149941:255;;;;150072:8;149941:255;;;;150105:10;149941:255;;;;;;150171:13;149941:255;;;149922:7;:16;149930:7;149922:16;;;;;;;;;;;:274;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;150251:10;150222:65;;150245:4;150236:7;150222:65;150263:8;150273:13;150222:65;;;;;;;:::i;:::-;;;;;;;;150327:10;150303:48;;150318:7;150303:48;150339:11;;150303:48;;;;;;:::i;:::-;;;;;;;;150369:7;150362:14;;;149146:1238;;;;;;:::o;139307:495::-;139440:7;139449:4;135462:15;:24;135478:7;135462:24;;;;;;;;;;;:31;135487:5;135462:31;;;;;;;;;;;;;;;;;;;;;;;;;135461:32;135439:141;;;;;;;;;;;;:::i;:::-;;;;;;;;;139520:31:::1;139533:4;139539:2;139543:7;139520:12;:31::i;:::-;139671:45;139694:4;139700:2;139704:7;139671:45;;;;;;;;;;;::::0;:22:::1;:45::i;:::-;139649:145;;;;;;;;;;;;:::i;:::-;;;;;;;;;139307:495:::0;;;;;:::o;158274:928::-;158422:28;158430:7;158439:10;158422:7;:28::i;:::-;158400:157;;;;;;;;;;;;:::i;:::-;;;;;;;;;158590:1;158576:16;;:2;:16;;;158568:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;158744:7;:16;158752:7;158744:16;;;;;;;;;;;:25;;;;;;;;;;;;158730:39;;:10;:39;;;:78;;;;158807:1;158773:7;:16;158781:7;158773:16;;;;;;;;;;;:30;;;:35;158730:78;158726:469;;;158825:42;158849:4;158855:2;158859:7;158825:23;:42::i;:::-;158975:1;158963:9;:13;158959:93;;;159005:10;158997:28;;:39;159026:9;158997:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;158959:93;158726:469;;;159136:47;159165:4;159171:2;159175:7;159136:28;:47::i;:::-;158726:469;158274:928;;;:::o;136380:301::-;136477:4;136502:16;136510:7;136502;:16::i;:::-;136494:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;136639:34;136665:7;136639;:16;136647:7;136639:16;;;;;;;;;;;:25;;:34;;;;:::i;:::-;136632:41;;136380:301;;;;:::o;152445:188::-;152506:7;152534:16;152542:7;152534;:16::i;:::-;152526:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;152600:7;:16;152608:7;152600:16;;;;;;;;;;;:25;;;;;;;;;;;;152593:32;;152445:188;;;:::o;154926:243::-;154998:18;155027:24;155063:17;155107:11;;155120:17;;155139:21;;;;;;;;;;;155099:62;;;;;;154926:243;;;:::o;137273:332::-;137355:13;137389:16;137397:7;137389;:16::i;:::-;137381:70;;;;;;;;;;;;:::i;:::-;;;;;;;;;137575:22;137595:1;137575:7;:16;137583:7;137575:16;;;;;;;;;;;:19;;:22;;;;:::i;:::-;137568:29;;137273:332;;;:::o;136942:323::-;137024:15;137091:1;137074:19;;:5;:19;;;137052:111;;;;;;;;;;;;:::i;:::-;;;;;;;;;137241:9;:16;137251:5;137241:16;;;;;;;;;;;;;;;;137234:23;;136942:323;;;:::o;9360:103::-;8571:13;:11;:13::i;:::-;9425:30:::1;9452:1;9425:18;:30::i;:::-;9360:103::o:0;148163:110::-;148225:7;148252:13;:11;:13::i;:::-;148245:20;;148163:110;:::o;153942:275::-;8571:13;:11;:13::i;:::-;154028:26:::1;154057:16;;154028:45;;154103:18;154084:16;:37;;;;154147:62;154170:18;154190;154147:62;;;;;;;:::i;:::-;;;;;;;;154017:200;153942:275:::0;:::o;137989:163::-;138089:4;138113:15;:24;138129:7;138113:24;;;;;;;;;;;:31;138138:5;138113:31;;;;;;;;;;;;;;;;;;;;;;;;;138106:38;;137989:163;;;;:::o;153401:106::-;153455:7;153482:17;;153475:24;;153401:106;:::o;8685:87::-;8731:7;8758:6;;;;;;;;;;;8751:13;;8685:87;:::o;142190:518::-;142266:28;142274:7;142283:10;142266:7;:28::i;:::-;142244:123;;;;;;;;;;;;:::i;:::-;;;;;;;;;142497:5;142457:45;;:15;:24;142473:7;142457:24;;;;;;;;;;;:36;142482:10;142457:36;;;;;;;;;;;;;;;;;;;;;;;;;:45;;;142435:147;;;;;;;;;;;;:::i;:::-;;;;;;;;;142632:4;142593:15;:24;142609:7;142593:24;;;;;;;;;;;:36;142618:10;142593:36;;;;;;;;;;;;;;;;:43;;;;;;;;;;;;;;;;;;142683:10;142652:48;;142674:7;142652:48;142695:4;142652:48;;;;;;:::i;:::-;;;;;;;;142190:518;:::o;137613:267::-;137675:7;137703:16;137711:7;137703;:16::i;:::-;137695:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;137834:38;137855:7;:16;137863:7;137855:16;;;;;;;;;;;137834:20;:38::i;:::-;137827:45;;137613:267;;;:::o;155469:413::-;155583:4;155608:16;155616:7;155608;:16::i;:::-;155600:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;155667:28;155698:7;:16;155706:7;155698:16;;;;;;;;;;;155667:47;;155831:5;:14;;;;;;;;;;;;155821:24;;:6;:24;;;:52;;;;155872:1;155849:5;:19;;;:24;155821:52;155813:61;;;155469:413;;;;:::o;148508:562::-;148596:19;;:::i;:::-;148636:16;148644:7;148636;:16::i;:::-;148628:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;148695:28;148726:7;:16;148734:7;148726:16;;;;;;;;;;;148695:47;;148773:289;;;;;;;;148814:5;:13;;;148773:289;;;;148857:5;:15;;148773:289;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;148897:5;:10;;;148773:289;;;;148936:5;:14;;;148773:289;;;;148979:5;:14;;;;;;;;;;;;148773:289;;;;;;149027:5;:19;;;148773:289;;;148753:309;;;148508:562;;;:::o;138339:178::-;138468:41;;;;;;;;;;:::i;:::-;;;;;;;;157748:437;157906:28;157914:7;157923:10;157906:7;:28::i;:::-;157884:157;;;;;;;;;;;;:::i;:::-;;;;;;;;;158074:1;158060:16;;:2;:16;;;158052:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;158130:47;158159:4;158165:2;158169:7;158130:28;:47::i;:::-;157748:437;;;:::o;153840:94::-;153888:7;153915:11;;153908:18;;153840:94;:::o;139810:527::-;139972:7;139981:4;135462:15;:24;135478:7;135462:24;;;;;;;;;;;:31;135487:5;135462:31;;;;;;;;;;;;;;;;;;;;;;;;;135461:32;135439:141;;;;;;;;;;;;:::i;:::-;;;;;;;;;140052:31:::1;140065:4;140071:2;140075:7;140052:12;:31::i;:::-;140203:48;140226:4;140232:2;140236:7;140245:5;140203:22;:48::i;:::-;140181:148;;;;;;;;;;;;:::i;:::-;;;;;;;;;139810:527:::0;;;;;;:::o;150392:1259::-;150522:16;150530:7;150522;:16::i;:::-;150514:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;150581:28;150612:7;:16;150620:7;150612:16;;;;;;;;;;;150581:47;;150675:5;:14;;;;;;;;;;;;150661:28;;:10;:28;;;150639:117;;;;;;;;;;;;:::i;:::-;;;;;;;;;150830:19;150852:23;150867:7;150852:14;:23::i;:::-;150830:45;;150886:19;150927:11;150908:16;;:30;;;;:::i;:::-;150886:52;;150980:11;150967:9;:24;;150959:79;;;;;;;;;;;;:::i;:::-;;;;;;;;;151122:1;151108:11;:15;151104:100;;;151148:21;;;;;;;;;;;151140:39;;:52;151180:11;151140:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;151104:100;151279:11;151267:9;:23;151263:109;;;151315:10;151307:28;;:53;151348:11;151336:9;:23;;;;:::i;:::-;151307:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;151263:109;151384:24;151411:5;:19;;;151384:46;;151463:16;151441:5;:19;;:38;;;;151518:7;151497:65;151527:16;151545;151497:65;;;;;;;:::i;:::-;;;;;;;;151606:10;151578:65;;151597:7;151578:65;151618:11;151631;151578:65;;;;;;;:::i;:::-;;;;;;;;150503:1148;;;;150392:1259;;:::o;151659:778::-;151776:16;151784:7;151776;:16::i;:::-;151768:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;151866:1;151843:25;;:11;:25;;;151835:80;;;;;;;;;;;;:::i;:::-;;;;;;;;;151936:28;151967:7;:16;151975:7;151967:16;;;;;;;;;;;151936:47;;152030:5;:14;;;;;;;;;;;;152016:28;;:10;:28;;;151994:126;;;;;;;;;;;;:::i;:::-;;;;;;;;;152168:5;:14;;;;;;;;;;;;152153:29;;:11;:29;;;152131:138;;;;;;;;;;;;:::i;:::-;;;;;;;;;152282:19;152304:5;:14;;;;;;;;;;;;152282:36;;152346:11;152329:5;:14;;;:28;;;;;;;;;;;;;;;;;;152417:11;152375:54;;152404:11;152375:54;;152395:7;152375:54;;;;;;;;;;151757:680;;151659:778;;:::o;154225:104::-;154278:7;154305:16;;154298:23;;154225:104;:::o;138692:192::-;138818:4;138835:41;;;;;;;;;;:::i;:::-;;;;;;;;153515:114;153573:7;153600:21;;;;;;;;;;;153593:28;;153515:114;:::o;155966:560::-;156072:7;156100:16;156108:7;156100;:16::i;:::-;156092:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;156159:28;156190:7;:16;156198:7;156190:16;;;;;;;;;;;156159:47;;156287:5;:14;;;;;;;;;;;;156277:24;;:6;:24;;;156273:65;;156325:1;156318:8;;;;;156273:65;156358:19;156380:5;:19;;;156358:41;;156410:19;156432:33;156453:11;156432:20;:33::i;:::-;156410:55;;156507:11;156493;:25;;;;:::i;:::-;156486:32;;;;;155966:560;;;;;:::o;9618:220::-;8571:13;:11;:13::i;:::-;9723:1:::1;9703:22;;:8;:22;;::::0;9699:93:::1;;9777:1;9749:31;;;;;;;;;;;:::i;:::-;;;;;;;;9699:93;9802:28;9821:8;9802:18;:28::i;:::-;9618:220:::0;:::o;152696:319::-;8571:13;:11;:13::i;:::-;146056:4:::1;152781:8;:34;;152773:74;;;;;;;;;;;;:::i;:::-;;;;;;;;;152868:16;152887:17;;152868:36;;152935:8;152915:17;:28;;;;152969:38;152988:8;152998;152969:38;;;;;;;:::i;:::-;;;;;;;;152762:253;152696:319:::0;:::o;156583:608::-;156698:19;156719;156740:17;156778:16;156786:7;156778;:16::i;:::-;156770:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;156837:28;156868:7;:16;156876:7;156868:16;;;;;;;;;;;156837:47;;156965:5;:14;;;;;;;;;;;;156955:24;;:6;:24;;;156951:73;;157004:1;157007;157010;156996:16;;;;;;;;;156951:73;157058:5;:19;;;157044:33;;157102;157123:11;157102:20;:33::i;:::-;157088:47;;157172:11;157158;:25;;;;:::i;:::-;157146:37;;156759:432;156583:608;;;;;;:::o;19183:148::-;19259:4;19298:25;19283:40;;;:11;:40;;;;19276:47;;19183:148;;;:::o;136689:118::-;136746:4;136798:1;136770:25;:7;:16;136778:7;136770:16;;;;;;;;;;;:23;:25::i;:::-;:29;136763:36;;136689:118;;;:::o;8850:166::-;8921:12;:10;:12::i;:::-;8910:23;;:7;:5;:7::i;:::-;:23;;;8906:103;;8984:12;:10;:12::i;:::-;8957:40;;;;;;;;;;;:::i;:::-;;;;;;;;8906:103;8850:166::o;6694:98::-;6747:7;6774:10;6767:17;;6694:98;:::o;128985:152::-;129055:4;129079:50;129084:3;:10;;129120:5;129104:23;;129096:32;;129079:4;:50::i;:::-;129072:57;;128985:152;;;;:::o;159210:306::-;159405:28;159415:4;159421:2;159425:7;159405:9;:28::i;:::-;159478:7;159474:2;159451:38;;159468:4;159451:38;;;159487:1;159451:38;;;;;;:::i;:::-;;;;;;;;159210:306;;;:::o;140523:996::-;140678:4;140782:1;140764:2;:14;;;:19;140760:63;;140807:4;140800:11;;;;140760:63;140868:2;140852:36;;;140907:10;140936:4;140959:7;140985:5;140852:153;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;140835:677;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;141189:1;141172:6;:13;:18;141168:333;;141211:60;;;;;;;;;;:::i;:::-;;;;;;;;141168:333;141459:6;141453:13;141444:6;141440:2;141436:15;141429:38;140835:677;141071:41;;;141061:51;;;:6;:51;;;;141054:58;;;140523:996;;;;;;;:::o;159524:1990::-;159659:28;159690:7;:16;159698:7;159690:16;;;;;;;;;;;159659:47;;159818:5;:14;;;;;;;;;;;;159804:28;;:10;:28;;;159800:526;;159918:28;159928:4;159934:2;159938:7;159918:9;:28::i;:::-;159993:7;159989:2;159966:38;;159983:4;159966:38;;;160002:1;159966:38;;;;;;:::i;:::-;;;;;;;;160089:2;160043:49;;160073:5;:14;;;;;;;;;;;;160043:49;;160064:7;160043:49;;;;;;;;;;160217:1;160205:9;:13;160201:93;;;160247:10;160239:28;;:39;160268:9;160239:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;160201:93;160308:7;;;159800:526;160397:19;160419:5;:19;;;160397:41;;160449:19;160471:33;160492:11;160471:20;:33::i;:::-;160449:55;;160515:21;160553:11;160539;:25;;;;:::i;:::-;160515:49;;160612:13;160599:9;:26;;160577:134;;;;;;;;;;;;:::i;:::-;;;;;;;;;160817:1;160803:11;:15;160799:93;;;160843:5;:14;;;;;;;;;;;;160835:32;;:45;160868:11;160835:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;160799:93;161012:1;160998:11;:15;160994:169;;;161038:21;;;;;;;;;;;161030:39;;:52;161070:11;161030:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;161127:10;161102:49;;161118:7;161102:49;161139:11;161102:49;;;;;;:::i;:::-;;;;;;;;160994:169;161238:13;161226:9;:25;161222:113;;;161276:10;161268:28;;:55;161309:13;161297:9;:25;;;;:::i;:::-;161268:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;161222:113;161412:28;161422:4;161428:2;161432:7;161412:9;:28::i;:::-;161485:7;161481:2;161458:48;;161475:4;161458:48;;;161494:11;161458:48;;;;;;:::i;:::-;;;;;;;;159648:1866;;;;159524:1990;;;;:::o;129964:167::-;130044:4;130068:55;130078:3;:10;;130114:5;130098:23;;130090:32;;130068:9;:55::i;:::-;130061:62;;129964:167;;;;:::o;130688:158::-;130762:7;130813:22;130817:3;:10;;130829:5;130813:3;:22::i;:::-;130805:31;;130782:56;;130688:158;;;;:::o;9998:191::-;10072:16;10091:6;;;;;;;;;;;10072:25;;10117:8;10108:6;;:17;;;;;;;;;;;;;;;;;;10172:8;10141:40;;10162:8;10141:40;;;;;;;;;;;;10061:128;9998:191;:::o;130217:117::-;130280:7;130307:19;130315:3;:10;;130307:7;:19::i;:::-;130300:26;;130217:117;;;:::o;121788:416::-;121851:4;121873:21;121883:3;121888:5;121873:9;:21::i;:::-;121868:329;;121911:3;:11;;121928:5;121911:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122096:3;:11;;:18;;;;122072:3;:14;;:21;122087:5;122072:21;;;;;;;;;;;:42;;;;122136:4;122129:11;;;;121868:329;122180:5;122173:12;;121788:416;;;;;:::o;141527:557::-;141631:22;141639:7;141648:4;141631:7;:22::i;:::-;141609:109;;;;;;;;;;;;:::i;:::-;;;;;;;;;141751:1;141737:16;;:2;:16;;;141729:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;141814:20;141822:7;141831:2;141814:7;:20::i;:::-;141813:21;141805:71;;;;;;;;;;;;:::i;:::-;;;;;;;;;141940:24;141961:2;141940:7;:16;141948:7;141940:16;;;;;;;;;;;:20;;:24;;;;:::i;:::-;;142022:1;142005:9;:13;142015:2;142005:13;;;;;;;;;;;;;;;;:18;;;;;;;:::i;:::-;;;;;;;;142041:35;142058:7;142067:4;142073:2;142041:35;;;;;;;;:::i;:::-;;;;;;;;141527:557;;;:::o;124431:131::-;124504:4;124553:1;124528:3;:14;;:21;124543:5;124528:21;;;;;;;;;;;;:26;;124521:33;;124431:131;;;;:::o;125111:120::-;125178:7;125205:3;:11;;125217:5;125205:18;;;;;;;;:::i;:::-;;;;;;;;;;125198:25;;125111:120;;;;:::o;124648:109::-;124704:7;124731:3;:11;;:18;;;;124724:25;;124648:109;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;7:75:1:-;40:6;73:2;67:9;57:19;;7:75;:::o;88:117::-;197:1;194;187:12;211:117;320:1;317;310:12;334:149;370:7;410:66;403:5;399:78;388:89;;334:149;;;:::o;489:120::-;561:23;578:5;561:23;:::i;:::-;554:5;551:34;541:62;;599:1;596;589:12;541:62;489:120;:::o;615:137::-;660:5;698:6;685:20;676:29;;714:32;740:5;714:32;:::i;:::-;615:137;;;;:::o;758:327::-;816:6;865:2;853:9;844:7;840:23;836:32;833:119;;;871:79;;:::i;:::-;833:119;991:1;1016:52;1060:7;1051:6;1040:9;1036:22;1016:52;:::i;:::-;1006:62;;962:116;758:327;;;;:::o;1091:90::-;1125:7;1168:5;1161:13;1154:21;1143:32;;1091:90;;;:::o;1187:109::-;1268:21;1283:5;1268:21;:::i;:::-;1263:3;1256:34;1187:109;;:::o;1302:210::-;1389:4;1427:2;1416:9;1412:18;1404:26;;1440:65;1502:1;1491:9;1487:17;1478:6;1440:65;:::i;:::-;1302:210;;;;:::o;1518:77::-;1555:7;1584:5;1573:16;;1518:77;;;:::o;1601:122::-;1674:24;1692:5;1674:24;:::i;:::-;1667:5;1664:35;1654:63;;1713:1;1710;1703:12;1654:63;1601:122;:::o;1729:139::-;1775:5;1813:6;1800:20;1791:29;;1829:33;1856:5;1829:33;:::i;:::-;1729:139;;;;:::o;1874:329::-;1933:6;1982:2;1970:9;1961:7;1957:23;1953:32;1950:119;;;1988:79;;:::i;:::-;1950:119;2108:1;2133:53;2178:7;2169:6;2158:9;2154:22;2133:53;:::i;:::-;2123:63;;2079:117;1874:329;;;;:::o;2209:126::-;2246:7;2286:42;2279:5;2275:54;2264:65;;2209:126;;;:::o;2341:96::-;2378:7;2407:24;2425:5;2407:24;:::i;:::-;2396:35;;2341:96;;;:::o;2443:118::-;2530:24;2548:5;2530:24;:::i;:::-;2525:3;2518:37;2443:118;;:::o;2567:222::-;2660:4;2698:2;2687:9;2683:18;2675:26;;2711:71;2779:1;2768:9;2764:17;2755:6;2711:71;:::i;:::-;2567:222;;;;:::o;2795:122::-;2868:24;2886:5;2868:24;:::i;:::-;2861:5;2858:35;2848:63;;2907:1;2904;2897:12;2848:63;2795:122;:::o;2923:139::-;2969:5;3007:6;2994:20;2985:29;;3023:33;3050:5;3023:33;:::i;:::-;2923:139;;;;:::o;3068:474::-;3136:6;3144;3193:2;3181:9;3172:7;3168:23;3164:32;3161:119;;;3199:79;;:::i;:::-;3161:119;3319:1;3344:53;3389:7;3380:6;3369:9;3365:22;3344:53;:::i;:::-;3334:63;;3290:117;3446:2;3472:53;3517:7;3508:6;3497:9;3493:22;3472:53;:::i;:::-;3462:63;;3417:118;3068:474;;;;;:::o;3548:118::-;3635:24;3653:5;3635:24;:::i;:::-;3630:3;3623:37;3548:118;;:::o;3672:222::-;3765:4;3803:2;3792:9;3788:18;3780:26;;3816:71;3884:1;3873:9;3869:17;3860:6;3816:71;:::i;:::-;3672:222;;;;:::o;3900:329::-;3959:6;4008:2;3996:9;3987:7;3983:23;3979:32;3976:119;;;4014:79;;:::i;:::-;3976:119;4134:1;4159:53;4204:7;4195:6;4184:9;4180:22;4159:53;:::i;:::-;4149:63;;4105:117;3900:329;;;;:::o;4235:619::-;4312:6;4320;4328;4377:2;4365:9;4356:7;4352:23;4348:32;4345:119;;;4383:79;;:::i;:::-;4345:119;4503:1;4528:53;4573:7;4564:6;4553:9;4549:22;4528:53;:::i;:::-;4518:63;;4474:117;4630:2;4656:53;4701:7;4692:6;4681:9;4677:22;4656:53;:::i;:::-;4646:63;;4601:118;4758:2;4784:53;4829:7;4820:6;4809:9;4805:22;4784:53;:::i;:::-;4774:63;;4729:118;4235:619;;;;;:::o;4860:99::-;4912:6;4946:5;4940:12;4930:22;;4860:99;;;:::o;4965:169::-;5049:11;5083:6;5078:3;5071:19;5123:4;5118:3;5114:14;5099:29;;4965:169;;;;:::o;5140:139::-;5229:6;5224:3;5219;5213:23;5270:1;5261:6;5256:3;5252:16;5245:27;5140:139;;;:::o;5285:102::-;5326:6;5377:2;5373:7;5368:2;5361:5;5357:14;5353:28;5343:38;;5285:102;;;:::o;5393:377::-;5481:3;5509:39;5542:5;5509:39;:::i;:::-;5564:71;5628:6;5623:3;5564:71;:::i;:::-;5557:78;;5644:65;5702:6;5697:3;5690:4;5683:5;5679:16;5644:65;:::i;:::-;5734:29;5756:6;5734:29;:::i;:::-;5729:3;5725:39;5718:46;;5485:285;5393:377;;;;:::o;5776:313::-;5889:4;5927:2;5916:9;5912:18;5904:26;;5976:9;5970:4;5966:20;5962:1;5951:9;5947:17;5940:47;6004:78;6077:4;6068:6;6004:78;:::i;:::-;5996:86;;5776:313;;;;:::o;6095:117::-;6204:1;6201;6194:12;6218:117;6327:1;6324;6317:12;6341:180;6389:77;6386:1;6379:88;6486:4;6483:1;6476:15;6510:4;6507:1;6500:15;6527:281;6610:27;6632:4;6610:27;:::i;:::-;6602:6;6598:40;6740:6;6728:10;6725:22;6704:18;6692:10;6689:34;6686:62;6683:88;;;6751:18;;:::i;:::-;6683:88;6791:10;6787:2;6780:22;6570:238;6527:281;;:::o;6814:129::-;6848:6;6875:20;;:::i;:::-;6865:30;;6904:33;6932:4;6924:6;6904:33;:::i;:::-;6814:129;;;:::o;6949:308::-;7011:4;7101:18;7093:6;7090:30;7087:56;;;7123:18;;:::i;:::-;7087:56;7161:29;7183:6;7161:29;:::i;:::-;7153:37;;7245:4;7239;7235:15;7227:23;;6949:308;;;:::o;7263:148::-;7361:6;7356:3;7351;7338:30;7402:1;7393:6;7388:3;7384:16;7377:27;7263:148;;;:::o;7417:425::-;7495:5;7520:66;7536:49;7578:6;7536:49;:::i;:::-;7520:66;:::i;:::-;7511:75;;7609:6;7602:5;7595:21;7647:4;7640:5;7636:16;7685:3;7676:6;7671:3;7667:16;7664:25;7661:112;;;7692:79;;:::i;:::-;7661:112;7782:54;7829:6;7824:3;7819;7782:54;:::i;:::-;7501:341;7417:425;;;;;:::o;7862:340::-;7918:5;7967:3;7960:4;7952:6;7948:17;7944:27;7934:122;;7975:79;;:::i;:::-;7934:122;8092:6;8079:20;8117:79;8192:3;8184:6;8177:4;8169:6;8165:17;8117:79;:::i;:::-;8108:88;;7924:278;7862:340;;;;:::o;8208:77::-;8245:7;8274:5;8263:16;;8208:77;;;:::o;8291:122::-;8364:24;8382:5;8364:24;:::i;:::-;8357:5;8354:35;8344:63;;8403:1;8400;8393:12;8344:63;8291:122;:::o;8419:139::-;8465:5;8503:6;8490:20;8481:29;;8519:33;8546:5;8519:33;:::i;:::-;8419:139;;;;:::o;8564:945::-;8660:6;8668;8676;8684;8733:3;8721:9;8712:7;8708:23;8704:33;8701:120;;;8740:79;;:::i;:::-;8701:120;8888:1;8877:9;8873:17;8860:31;8918:18;8910:6;8907:30;8904:117;;;8940:79;;:::i;:::-;8904:117;9045:63;9100:7;9091:6;9080:9;9076:22;9045:63;:::i;:::-;9035:73;;8831:287;9157:2;9183:53;9228:7;9219:6;9208:9;9204:22;9183:53;:::i;:::-;9173:63;;9128:118;9285:2;9311:53;9356:7;9347:6;9336:9;9332:22;9311:53;:::i;:::-;9301:63;;9256:118;9413:2;9439:53;9484:7;9475:6;9464:9;9460:22;9439:53;:::i;:::-;9429:63;;9384:118;8564:945;;;;;;;:::o;9515:474::-;9583:6;9591;9640:2;9628:9;9619:7;9615:23;9611:32;9608:119;;;9646:79;;:::i;:::-;9608:119;9766:1;9791:53;9836:7;9827:6;9816:9;9812:22;9791:53;:::i;:::-;9781:63;;9737:117;9893:2;9919:53;9964:7;9955:6;9944:9;9940:22;9919:53;:::i;:::-;9909:63;;9864:118;9515:474;;;;;:::o;9995:442::-;10144:4;10182:2;10171:9;10167:18;10159:26;;10195:71;10263:1;10252:9;10248:17;10239:6;10195:71;:::i;:::-;10276:72;10344:2;10333:9;10329:18;10320:6;10276:72;:::i;:::-;10358;10426:2;10415:9;10411:18;10402:6;10358:72;:::i;:::-;9995:442;;;;;;:::o;10443:108::-;10520:24;10538:5;10520:24;:::i;:::-;10515:3;10508:37;10443:108;;:::o;10557:159::-;10631:11;10665:6;10660:3;10653:19;10705:4;10700:3;10696:14;10681:29;;10557:159;;;;:::o;10722:357::-;10800:3;10828:39;10861:5;10828:39;:::i;:::-;10883:61;10937:6;10932:3;10883:61;:::i;:::-;10876:68;;10953:65;11011:6;11006:3;10999:4;10992:5;10988:16;10953:65;:::i;:::-;11043:29;11065:6;11043:29;:::i;:::-;11038:3;11034:39;11027:46;;10804:275;10722:357;;;;:::o;11085:108::-;11162:24;11180:5;11162:24;:::i;:::-;11157:3;11150:37;11085:108;;:::o;11199:::-;11276:24;11294:5;11276:24;:::i;:::-;11271:3;11264:37;11199:108;;:::o;11391:1337::-;11520:3;11556:4;11551:3;11547:14;11646:4;11639:5;11635:16;11629:23;11665:63;11722:4;11717:3;11713:14;11699:12;11665:63;:::i;:::-;11571:167;11825:4;11818:5;11814:16;11808:23;11878:3;11872:4;11868:14;11861:4;11856:3;11852:14;11845:38;11904:73;11972:4;11958:12;11904:73;:::i;:::-;11896:81;;11748:240;12070:4;12063:5;12059:16;12053:23;12089:63;12146:4;12141:3;12137:14;12123:12;12089:63;:::i;:::-;11998:164;12248:4;12241:5;12237:16;12231:23;12267:63;12324:4;12319:3;12315:14;12301:12;12267:63;:::i;:::-;12172:168;12426:4;12419:5;12415:16;12409:23;12445:63;12502:4;12497:3;12493:14;12479:12;12445:63;:::i;:::-;12350:168;12609:4;12602:5;12598:16;12592:23;12628:63;12685:4;12680:3;12676:14;12662:12;12628:63;:::i;:::-;12528:173;12718:4;12711:11;;11525:1203;11391:1337;;;;:::o;12734:393::-;12887:4;12925:2;12914:9;12910:18;12902:26;;12974:9;12968:4;12964:20;12960:1;12949:9;12945:17;12938:47;13002:118;13115:4;13106:6;13002:118;:::i;:::-;12994:126;;12734:393;;;;:::o;13133:116::-;13203:21;13218:5;13203:21;:::i;:::-;13196:5;13193:32;13183:60;;13239:1;13236;13229:12;13183:60;13133:116;:::o;13255:133::-;13298:5;13336:6;13323:20;13314:29;;13352:30;13376:5;13352:30;:::i;:::-;13255:133;;;;:::o;13394:468::-;13459:6;13467;13516:2;13504:9;13495:7;13491:23;13487:32;13484:119;;;13522:79;;:::i;:::-;13484:119;13642:1;13667:53;13712:7;13703:6;13692:9;13688:22;13667:53;:::i;:::-;13657:63;;13613:117;13769:2;13795:50;13837:7;13828:6;13817:9;13813:22;13795:50;:::i;:::-;13785:60;;13740:115;13394:468;;;;;:::o;13868:307::-;13929:4;14019:18;14011:6;14008:30;14005:56;;;14041:18;;:::i;:::-;14005:56;14079:29;14101:6;14079:29;:::i;:::-;14071:37;;14163:4;14157;14153:15;14145:23;;13868:307;;;:::o;14181:423::-;14258:5;14283:65;14299:48;14340:6;14299:48;:::i;:::-;14283:65;:::i;:::-;14274:74;;14371:6;14364:5;14357:21;14409:4;14402:5;14398:16;14447:3;14438:6;14433:3;14429:16;14426:25;14423:112;;;14454:79;;:::i;:::-;14423:112;14544:54;14591:6;14586:3;14581;14544:54;:::i;:::-;14264:340;14181:423;;;;;:::o;14623:338::-;14678:5;14727:3;14720:4;14712:6;14708:17;14704:27;14694:122;;14735:79;;:::i;:::-;14694:122;14852:6;14839:20;14877:78;14951:3;14943:6;14936:4;14928:6;14924:17;14877:78;:::i;:::-;14868:87;;14684:277;14623:338;;;;:::o;14967:943::-;15062:6;15070;15078;15086;15135:3;15123:9;15114:7;15110:23;15106:33;15103:120;;;15142:79;;:::i;:::-;15103:120;15262:1;15287:53;15332:7;15323:6;15312:9;15308:22;15287:53;:::i;:::-;15277:63;;15233:117;15389:2;15415:53;15460:7;15451:6;15440:9;15436:22;15415:53;:::i;:::-;15405:63;;15360:118;15517:2;15543:53;15588:7;15579:6;15568:9;15564:22;15543:53;:::i;:::-;15533:63;;15488:118;15673:2;15662:9;15658:18;15645:32;15704:18;15696:6;15693:30;15690:117;;;15726:79;;:::i;:::-;15690:117;15831:62;15885:7;15876:6;15865:9;15861:22;15831:62;:::i;:::-;15821:72;;15616:287;14967:943;;;;;;;:::o;15916:474::-;15984:6;15992;16041:2;16029:9;16020:7;16016:23;16012:32;16009:119;;;16047:79;;:::i;:::-;16009:119;16167:1;16192:53;16237:7;16228:6;16217:9;16213:22;16192:53;:::i;:::-;16182:63;;16138:117;16294:2;16320:53;16365:7;16356:6;16345:9;16341:22;16320:53;:::i;:::-;16310:63;;16265:118;15916:474;;;;;:::o;16396:::-;16464:6;16472;16521:2;16509:9;16500:7;16496:23;16492:32;16489:119;;;16527:79;;:::i;:::-;16489:119;16647:1;16672:53;16717:7;16708:6;16697:9;16693:22;16672:53;:::i;:::-;16662:63;;16618:117;16774:2;16800:53;16845:7;16836:6;16825:9;16821:22;16800:53;:::i;:::-;16790:63;;16745:118;16396:474;;;;;:::o;16876:442::-;17025:4;17063:2;17052:9;17048:18;17040:26;;17076:71;17144:1;17133:9;17129:17;17120:6;17076:71;:::i;:::-;17157:72;17225:2;17214:9;17210:18;17201:6;17157:72;:::i;:::-;17239;17307:2;17296:9;17292:18;17283:6;17239:72;:::i;:::-;16876:442;;;;;;:::o;17324:181::-;17464:33;17460:1;17452:6;17448:14;17441:57;17324:181;:::o;17511:366::-;17653:3;17674:67;17738:2;17733:3;17674:67;:::i;:::-;17667:74;;17750:93;17839:3;17750:93;:::i;:::-;17868:2;17863:3;17859:12;17852:19;;17511:366;;;:::o;17883:419::-;18049:4;18087:2;18076:9;18072:18;18064:26;;18136:9;18130:4;18126:20;18122:1;18111:9;18107:17;18100:47;18164:131;18290:4;18164:131;:::i;:::-;18156:139;;17883:419;;;:::o;18308:180::-;18356:77;18353:1;18346:88;18453:4;18450:1;18443:15;18477:4;18474:1;18467:15;18494:410;18534:7;18557:20;18575:1;18557:20;:::i;:::-;18552:25;;18591:20;18609:1;18591:20;:::i;:::-;18586:25;;18646:1;18643;18639:9;18668:30;18686:11;18668:30;:::i;:::-;18657:41;;18847:1;18838:7;18834:15;18831:1;18828:22;18808:1;18801:9;18781:83;18758:139;;18877:18;;:::i;:::-;18758:139;18542:362;18494:410;;;;:::o;18910:180::-;18958:77;18955:1;18948:88;19055:4;19052:1;19045:15;19079:4;19076:1;19069:15;19096:185;19136:1;19153:20;19171:1;19153:20;:::i;:::-;19148:25;;19187:20;19205:1;19187:20;:::i;:::-;19182:25;;19226:1;19216:35;;19231:18;;:::i;:::-;19216:35;19273:1;19270;19266:9;19261:14;;19096:185;;;;:::o;19287:177::-;19427:29;19423:1;19415:6;19411:14;19404:53;19287:177;:::o;19470:366::-;19612:3;19633:67;19697:2;19692:3;19633:67;:::i;:::-;19626:74;;19709:93;19798:3;19709:93;:::i;:::-;19827:2;19822:3;19818:12;19811:19;;19470:366;;;:::o;19842:419::-;20008:4;20046:2;20035:9;20031:18;20023:26;;20095:9;20089:4;20085:20;20081:1;20070:9;20066:17;20059:47;20123:131;20249:4;20123:131;:::i;:::-;20115:139;;19842:419;;;:::o;20267:232::-;20407:34;20403:1;20395:6;20391:14;20384:58;20476:15;20471:2;20463:6;20459:15;20452:40;20267:232;:::o;20505:366::-;20647:3;20668:67;20732:2;20727:3;20668:67;:::i;:::-;20661:74;;20744:93;20833:3;20744:93;:::i;:::-;20862:2;20857:3;20853:12;20846:19;;20505:366;;;:::o;20877:419::-;21043:4;21081:2;21070:9;21066:18;21058:26;;21130:9;21124:4;21120:20;21116:1;21105:9;21101:17;21094:47;21158:131;21284:4;21158:131;:::i;:::-;21150:139;;20877:419;;;:::o;21302:332::-;21423:4;21461:2;21450:9;21446:18;21438:26;;21474:71;21542:1;21531:9;21527:17;21518:6;21474:71;:::i;:::-;21555:72;21623:2;21612:9;21608:18;21599:6;21555:72;:::i;:::-;21302:332;;;;;:::o;21640:233::-;21679:3;21702:24;21720:5;21702:24;:::i;:::-;21693:33;;21748:66;21741:5;21738:77;21735:103;;21818:18;;:::i;:::-;21735:103;21865:1;21858:5;21854:13;21847:20;;21640:233;;;:::o;21879:191::-;21919:3;21938:20;21956:1;21938:20;:::i;:::-;21933:25;;21972:20;21990:1;21972:20;:::i;:::-;21967:25;;22015:1;22012;22008:9;22001:16;;22036:3;22033:1;22030:10;22027:36;;;22043:18;;:::i;:::-;22027:36;21879:191;;;;:::o;22076:332::-;22197:4;22235:2;22224:9;22220:18;22212:26;;22248:71;22316:1;22305:9;22301:17;22292:6;22248:71;:::i;:::-;22329:72;22397:2;22386:9;22382:18;22373:6;22329:72;:::i;:::-;22076:332;;;;;:::o;22414:::-;22535:4;22573:2;22562:9;22558:18;22550:26;;22586:71;22654:1;22643:9;22639:17;22630:6;22586:71;:::i;:::-;22667:72;22735:2;22724:9;22720:18;22711:6;22667:72;:::i;:::-;22414:332;;;;;:::o;22752:226::-;22892:34;22888:1;22880:6;22876:14;22869:58;22961:9;22956:2;22948:6;22944:15;22937:34;22752:226;:::o;22984:366::-;23126:3;23147:67;23211:2;23206:3;23147:67;:::i;:::-;23140:74;;23223:93;23312:3;23223:93;:::i;:::-;23341:2;23336:3;23332:12;23325:19;;22984:366;;;:::o;23356:419::-;23522:4;23560:2;23549:9;23545:18;23537:26;;23609:9;23603:4;23599:20;23595:1;23584:9;23580:17;23573:47;23637:131;23763:4;23637:131;:::i;:::-;23629:139;;23356:419;;;:::o;23781:223::-;23921:34;23917:1;23909:6;23905:14;23898:58;23990:6;23985:2;23977:6;23973:15;23966:31;23781:223;:::o;24010:366::-;24152:3;24173:67;24237:2;24232:3;24173:67;:::i;:::-;24166:74;;24249:93;24338:3;24249:93;:::i;:::-;24367:2;24362:3;24358:12;24351:19;;24010:366;;;:::o;24382:419::-;24548:4;24586:2;24575:9;24571:18;24563:26;;24635:9;24629:4;24625:20;24621:1;24610:9;24606:17;24599:47;24663:131;24789:4;24663:131;:::i;:::-;24655:139;;24382:419;;;:::o;24807:180::-;24855:77;24852:1;24845:88;24952:4;24949:1;24942:15;24976:4;24973:1;24966:15;24993:320;25037:6;25074:1;25068:4;25064:12;25054:22;;25121:1;25115:4;25111:12;25142:18;25132:81;;25198:4;25190:6;25186:17;25176:27;;25132:81;25260:2;25252:6;25249:14;25229:18;25226:38;25223:84;;25279:18;;:::i;:::-;25223:84;25044:269;24993:320;;;:::o;25319:174::-;25459:26;25455:1;25447:6;25443:14;25436:50;25319:174;:::o;25499:366::-;25641:3;25662:67;25726:2;25721:3;25662:67;:::i;:::-;25655:74;;25738:93;25827:3;25738:93;:::i;:::-;25856:2;25851:3;25847:12;25840:19;;25499:366;;;:::o;25871:419::-;26037:4;26075:2;26064:9;26060:18;26052:26;;26124:9;26118:4;26114:20;26110:1;26099:9;26095:17;26088:47;26152:131;26278:4;26152:131;:::i;:::-;26144:139;;25871:419;;;:::o;26296:194::-;26336:4;26356:20;26374:1;26356:20;:::i;:::-;26351:25;;26390:20;26408:1;26390:20;:::i;:::-;26385:25;;26434:1;26431;26427:9;26419:17;;26458:1;26452:4;26449:11;26446:37;;;26463:18;;:::i;:::-;26446:37;26296:194;;;;:::o;26496:141::-;26545:4;26568:3;26560:11;;26591:3;26588:1;26581:14;26625:4;26622:1;26612:18;26604:26;;26496:141;;;:::o;26643:93::-;26680:6;26727:2;26722;26715:5;26711:14;26707:23;26697:33;;26643:93;;;:::o;26742:107::-;26786:8;26836:5;26830:4;26826:16;26805:37;;26742:107;;;;:::o;26855:393::-;26924:6;26974:1;26962:10;26958:18;26997:97;27027:66;27016:9;26997:97;:::i;:::-;27115:39;27145:8;27134:9;27115:39;:::i;:::-;27103:51;;27187:4;27183:9;27176:5;27172:21;27163:30;;27236:4;27226:8;27222:19;27215:5;27212:30;27202:40;;26931:317;;26855:393;;;;;:::o;27254:60::-;27282:3;27303:5;27296:12;;27254:60;;;:::o;27320:142::-;27370:9;27403:53;27421:34;27430:24;27448:5;27430:24;:::i;:::-;27421:34;:::i;:::-;27403:53;:::i;:::-;27390:66;;27320:142;;;:::o;27468:75::-;27511:3;27532:5;27525:12;;27468:75;;;:::o;27549:269::-;27659:39;27690:7;27659:39;:::i;:::-;27720:91;27769:41;27793:16;27769:41;:::i;:::-;27761:6;27754:4;27748:11;27720:91;:::i;:::-;27714:4;27707:105;27625:193;27549:269;;;:::o;27824:73::-;27869:3;27890:1;27883:8;;27824:73;:::o;27903:189::-;27980:32;;:::i;:::-;28021:65;28079:6;28071;28065:4;28021:65;:::i;:::-;27956:136;27903:189;;:::o;28098:186::-;28158:120;28175:3;28168:5;28165:14;28158:120;;;28229:39;28266:1;28259:5;28229:39;:::i;:::-;28202:1;28195:5;28191:13;28182:22;;28158:120;;;28098:186;;:::o;28290:543::-;28391:2;28386:3;28383:11;28380:446;;;28425:38;28457:5;28425:38;:::i;:::-;28509:29;28527:10;28509:29;:::i;:::-;28499:8;28495:44;28692:2;28680:10;28677:18;28674:49;;;28713:8;28698:23;;28674:49;28736:80;28792:22;28810:3;28792:22;:::i;:::-;28782:8;28778:37;28765:11;28736:80;:::i;:::-;28395:431;;28380:446;28290:543;;;:::o;28839:117::-;28893:8;28943:5;28937:4;28933:16;28912:37;;28839:117;;;;:::o;28962:169::-;29006:6;29039:51;29087:1;29083:6;29075:5;29072:1;29068:13;29039:51;:::i;:::-;29035:56;29120:4;29114;29110:15;29100:25;;29013:118;28962:169;;;;:::o;29136:295::-;29212:4;29358:29;29383:3;29377:4;29358:29;:::i;:::-;29350:37;;29420:3;29417:1;29413:11;29407:4;29404:21;29396:29;;29136:295;;;;:::o;29436:1395::-;29553:37;29586:3;29553:37;:::i;:::-;29655:18;29647:6;29644:30;29641:56;;;29677:18;;:::i;:::-;29641:56;29721:38;29753:4;29747:11;29721:38;:::i;:::-;29806:67;29866:6;29858;29852:4;29806:67;:::i;:::-;29900:1;29924:4;29911:17;;29956:2;29948:6;29945:14;29973:1;29968:618;;;;30630:1;30647:6;30644:77;;;30696:9;30691:3;30687:19;30681:26;30672:35;;30644:77;30747:67;30807:6;30800:5;30747:67;:::i;:::-;30741:4;30734:81;30603:222;29938:887;;29968:618;30020:4;30016:9;30008:6;30004:22;30054:37;30086:4;30054:37;:::i;:::-;30113:1;30127:208;30141:7;30138:1;30135:14;30127:208;;;30220:9;30215:3;30211:19;30205:26;30197:6;30190:42;30271:1;30263:6;30259:14;30249:24;;30318:2;30307:9;30303:18;30290:31;;30164:4;30161:1;30157:12;30152:17;;30127:208;;;30363:6;30354:7;30351:19;30348:179;;;30421:9;30416:3;30412:19;30406:26;30464:48;30506:4;30498:6;30494:17;30483:9;30464:48;:::i;:::-;30456:6;30449:64;30371:156;30348:179;30573:1;30569;30561:6;30557:14;30553:22;30547:4;30540:36;29975:611;;;29938:887;;29528:1303;;;29436:1395;;:::o;30837:118::-;30924:24;30942:5;30924:24;:::i;:::-;30919:3;30912:37;30837:118;;:::o;30961:332::-;31082:4;31120:2;31109:9;31105:18;31097:26;;31133:71;31201:1;31190:9;31186:17;31177:6;31133:71;:::i;:::-;31214:72;31282:2;31271:9;31267:18;31258:6;31214:72;:::i;:::-;30961:332;;;;;:::o;31299:246::-;31439:34;31435:1;31427:6;31423:14;31416:58;31508:29;31503:2;31495:6;31491:15;31484:54;31299:246;:::o;31551:366::-;31693:3;31714:67;31778:2;31773:3;31714:67;:::i;:::-;31707:74;;31790:93;31879:3;31790:93;:::i;:::-;31908:2;31903:3;31899:12;31892:19;;31551:366;;;:::o;31923:419::-;32089:4;32127:2;32116:9;32112:18;32104:26;;32176:9;32170:4;32166:20;32162:1;32151:9;32147:17;32140:47;32204:131;32330:4;32204:131;:::i;:::-;32196:139;;31923:419;;;:::o;32348:237::-;32488:34;32484:1;32476:6;32472:14;32465:58;32557:20;32552:2;32544:6;32540:15;32533:45;32348:237;:::o;32591:366::-;32733:3;32754:67;32818:2;32813:3;32754:67;:::i;:::-;32747:74;;32830:93;32919:3;32830:93;:::i;:::-;32948:2;32943:3;32939:12;32932:19;;32591:366;;;:::o;32963:419::-;33129:4;33167:2;33156:9;33152:18;33144:26;;33216:9;33210:4;33206:20;33202:1;33191:9;33187:17;33180:47;33244:131;33370:4;33244:131;:::i;:::-;33236:139;;32963:419;;;:::o;33388:178::-;33528:30;33524:1;33516:6;33512:14;33505:54;33388:178;:::o;33572:366::-;33714:3;33735:67;33799:2;33794:3;33735:67;:::i;:::-;33728:74;;33811:93;33900:3;33811:93;:::i;:::-;33929:2;33924:3;33920:12;33913:19;;33572:366;;;:::o;33944:419::-;34110:4;34148:2;34137:9;34133:18;34125:26;;34197:9;34191:4;34187:20;34183:1;34172:9;34168:17;34161:47;34225:131;34351:4;34225:131;:::i;:::-;34217:139;;33944:419;;;:::o;34369:228::-;34509:34;34505:1;34497:6;34493:14;34486:58;34578:11;34573:2;34565:6;34561:15;34554:36;34369:228;:::o;34603:366::-;34745:3;34766:67;34830:2;34825:3;34766:67;:::i;:::-;34759:74;;34842:93;34931:3;34842:93;:::i;:::-;34960:2;34955:3;34951:12;34944:19;;34603:366;;;:::o;34975:419::-;35141:4;35179:2;35168:9;35164:18;35156:26;;35228:9;35222:4;35218:20;35214:1;35203:9;35199:17;35192:47;35256:131;35382:4;35256:131;:::i;:::-;35248:139;;34975:419;;;:::o;35400:229::-;35540:34;35536:1;35528:6;35524:14;35517:58;35609:12;35604:2;35596:6;35592:15;35585:37;35400:229;:::o;35635:366::-;35777:3;35798:67;35862:2;35857:3;35798:67;:::i;:::-;35791:74;;35874:93;35963:3;35874:93;:::i;:::-;35992:2;35987:3;35983:12;35976:19;;35635:366;;;:::o;36007:419::-;36173:4;36211:2;36200:9;36196:18;36188:26;;36260:9;36254:4;36250:20;36246:1;36235:9;36231:17;36224:47;36288:131;36414:4;36288:131;:::i;:::-;36280:139;;36007:419;;;:::o;36432:232::-;36572:34;36568:1;36560:6;36556:14;36549:58;36641:15;36636:2;36628:6;36624:15;36617:40;36432:232;:::o;36670:366::-;36812:3;36833:67;36897:2;36892:3;36833:67;:::i;:::-;36826:74;;36909:93;36998:3;36909:93;:::i;:::-;37027:2;37022:3;37018:12;37011:19;;36670:366;;;:::o;37042:419::-;37208:4;37246:2;37235:9;37231:18;37223:26;;37295:9;37289:4;37285:20;37281:1;37270:9;37266:17;37259:47;37323:131;37449:4;37323:131;:::i;:::-;37315:139;;37042:419;;;:::o;37467:239::-;37607:34;37603:1;37595:6;37591:14;37584:58;37676:22;37671:2;37663:6;37659:15;37652:47;37467:239;:::o;37712:366::-;37854:3;37875:67;37939:2;37934:3;37875:67;:::i;:::-;37868:74;;37951:93;38040:3;37951:93;:::i;:::-;38069:2;38064:3;38060:12;38053:19;;37712:366;;;:::o;38084:419::-;38250:4;38288:2;38277:9;38273:18;38265:26;;38337:9;38331:4;38327:20;38323:1;38312:9;38308:17;38301:47;38365:131;38491:4;38365:131;:::i;:::-;38357:139;;38084:419;;;:::o;38509:226::-;38649:34;38645:1;38637:6;38633:14;38626:58;38718:9;38713:2;38705:6;38701:15;38694:34;38509:226;:::o;38741:366::-;38883:3;38904:67;38968:2;38963:3;38904:67;:::i;:::-;38897:74;;38980:93;39069:3;38980:93;:::i;:::-;39098:2;39093:3;39089:12;39082:19;;38741:366;;;:::o;39113:419::-;39279:4;39317:2;39306:9;39302:18;39294:26;;39366:9;39360:4;39356:20;39352:1;39341:9;39337:17;39330:47;39394:131;39520:4;39394:131;:::i;:::-;39386:139;;39113:419;;;:::o;39538:229::-;39678:34;39674:1;39666:6;39662:14;39655:58;39747:12;39742:2;39734:6;39730:15;39723:37;39538:229;:::o;39773:366::-;39915:3;39936:67;40000:2;39995:3;39936:67;:::i;:::-;39929:74;;40012:93;40101:3;40012:93;:::i;:::-;40130:2;40125:3;40121:12;40114:19;;39773:366;;;:::o;40145:419::-;40311:4;40349:2;40338:9;40334:18;40326:26;;40398:9;40392:4;40388:20;40384:1;40373:9;40369:17;40362:47;40426:131;40552:4;40426:131;:::i;:::-;40418:139;;40145:419;;;:::o;40570:229::-;40710:34;40706:1;40698:6;40694:14;40687:58;40779:12;40774:2;40766:6;40762:15;40755:37;40570:229;:::o;40805:366::-;40947:3;40968:67;41032:2;41027:3;40968:67;:::i;:::-;40961:74;;41044:93;41133:3;41044:93;:::i;:::-;41162:2;41157:3;41153:12;41146:19;;40805:366;;;:::o;41177:419::-;41343:4;41381:2;41370:9;41366:18;41358:26;;41430:9;41424:4;41420:20;41416:1;41405:9;41401:17;41394:47;41458:131;41584:4;41458:131;:::i;:::-;41450:139;;41177:419;;;:::o;41602:235::-;41742:34;41738:1;41730:6;41726:14;41719:58;41811:18;41806:2;41798:6;41794:15;41787:43;41602:235;:::o;41843:366::-;41985:3;42006:67;42070:2;42065:3;42006:67;:::i;:::-;41999:74;;42082:93;42171:3;42082:93;:::i;:::-;42200:2;42195:3;42191:12;42184:19;;41843:366;;;:::o;42215:419::-;42381:4;42419:2;42408:9;42404:18;42396:26;;42468:9;42462:4;42458:20;42454:1;42443:9;42439:17;42432:47;42496:131;42622:4;42496:131;:::i;:::-;42488:139;;42215:419;;;:::o;42640:246::-;42780:34;42776:1;42768:6;42764:14;42757:58;42849:29;42844:2;42836:6;42832:15;42825:54;42640:246;:::o;42892:366::-;43034:3;43055:67;43119:2;43114:3;43055:67;:::i;:::-;43048:74;;43131:93;43220:3;43131:93;:::i;:::-;43249:2;43244:3;43240:12;43233:19;;42892:366;;;:::o;43264:419::-;43430:4;43468:2;43457:9;43453:18;43445:26;;43517:9;43511:4;43507:20;43503:1;43492:9;43488:17;43481:47;43545:131;43671:4;43545:131;:::i;:::-;43537:139;;43264:419;;;:::o;43689:177::-;43829:29;43825:1;43817:6;43813:14;43806:53;43689:177;:::o;43872:366::-;44014:3;44035:67;44099:2;44094:3;44035:67;:::i;:::-;44028:74;;44111:93;44200:3;44111:93;:::i;:::-;44229:2;44224:3;44220:12;44213:19;;43872:366;;;:::o;44244:419::-;44410:4;44448:2;44437:9;44433:18;44425:26;;44497:9;44491:4;44487:20;44483:1;44472:9;44468:17;44461:47;44525:131;44651:4;44525:131;:::i;:::-;44517:139;;44244:419;;;:::o;44669:85::-;44714:7;44743:5;44732:16;;44669:85;;;:::o;44760:158::-;44818:9;44851:61;44869:42;44878:32;44904:5;44878:32;:::i;:::-;44869:42;:::i;:::-;44851:61;:::i;:::-;44838:74;;44760:158;;;:::o;44924:147::-;45019:45;45058:5;45019:45;:::i;:::-;45014:3;45007:58;44924:147;;:::o;45077:238::-;45178:4;45216:2;45205:9;45201:18;45193:26;;45229:79;45305:1;45294:9;45290:17;45281:6;45229:79;:::i;:::-;45077:238;;;;:::o;45321:98::-;45372:6;45406:5;45400:12;45390:22;;45321:98;;;:::o;45425:168::-;45508:11;45542:6;45537:3;45530:19;45582:4;45577:3;45573:14;45558:29;;45425:168;;;;:::o;45599:373::-;45685:3;45713:38;45745:5;45713:38;:::i;:::-;45767:70;45830:6;45825:3;45767:70;:::i;:::-;45760:77;;45846:65;45904:6;45899:3;45892:4;45885:5;45881:16;45846:65;:::i;:::-;45936:29;45958:6;45936:29;:::i;:::-;45931:3;45927:39;45920:46;;45689:283;45599:373;;;;:::o;45978:640::-;46173:4;46211:3;46200:9;46196:19;46188:27;;46225:71;46293:1;46282:9;46278:17;46269:6;46225:71;:::i;:::-;46306:72;46374:2;46363:9;46359:18;46350:6;46306:72;:::i;:::-;46388;46456:2;46445:9;46441:18;46432:6;46388:72;:::i;:::-;46507:9;46501:4;46497:20;46492:2;46481:9;46477:18;46470:48;46535:76;46606:4;46597:6;46535:76;:::i;:::-;46527:84;;45978:640;;;;;;;:::o;46624:141::-;46680:5;46711:6;46705:13;46696:22;;46727:32;46753:5;46727:32;:::i;:::-;46624:141;;;;:::o;46771:349::-;46840:6;46889:2;46877:9;46868:7;46864:23;46860:32;46857:119;;;46895:79;;:::i;:::-;46857:119;47015:1;47040:63;47095:7;47086:6;47075:9;47071:22;47040:63;:::i;:::-;47030:73;;46986:127;46771:349;;;;:::o;47126:245::-;47266:34;47262:1;47254:6;47250:14;47243:58;47335:28;47330:2;47322:6;47318:15;47311:53;47126:245;:::o;47377:366::-;47519:3;47540:67;47604:2;47599:3;47540:67;:::i;:::-;47533:74;;47616:93;47705:3;47616:93;:::i;:::-;47734:2;47729:3;47725:12;47718:19;;47377:366;;;:::o;47749:419::-;47915:4;47953:2;47942:9;47938:18;47930:26;;48002:9;47996:4;47992:20;47988:1;47977:9;47973:17;47966:47;48030:131;48156:4;48030:131;:::i;:::-;48022:139;;47749:419;;;:::o;48174:224::-;48314:34;48310:1;48302:6;48298:14;48291:58;48383:7;48378:2;48370:6;48366:15;48359:32;48174:224;:::o;48404:366::-;48546:3;48567:67;48631:2;48626:3;48567:67;:::i;:::-;48560:74;;48643:93;48732:3;48643:93;:::i;:::-;48761:2;48756:3;48752:12;48745:19;;48404:366;;;:::o;48776:419::-;48942:4;48980:2;48969:9;48965:18;48957:26;;49029:9;49023:4;49019:20;49015:1;49004:9;49000:17;48993:47;49057:131;49183:4;49057:131;:::i;:::-;49049:139;;48776:419;;;:::o;49201:224::-;49341:34;49337:1;49329:6;49325:14;49318:58;49410:7;49405:2;49397:6;49393:15;49386:32;49201:224;:::o;49431:366::-;49573:3;49594:67;49658:2;49653:3;49594:67;:::i;:::-;49587:74;;49670:93;49759:3;49670:93;:::i;:::-;49788:2;49783:3;49779:12;49772:19;;49431:366;;;:::o;49803:419::-;49969:4;50007:2;49996:9;49992:18;49984:26;;50056:9;50050:4;50046:20;50042:1;50031:9;50027:17;50020:47;50084:131;50210:4;50084:131;:::i;:::-;50076:139;;49803:419;;;:::o;50228:442::-;50377:4;50415:2;50404:9;50400:18;50392:26;;50428:71;50496:1;50485:9;50481:17;50472:6;50428:71;:::i;:::-;50509:72;50577:2;50566:9;50562:18;50553:6;50509:72;:::i;:::-;50591;50659:2;50648:9;50644:18;50635:6;50591:72;:::i;:::-;50228:442;;;;;;:::o;50676:180::-;50724:77;50721:1;50714:88;50821:4;50818:1;50811:15;50845:4;50842:1;50835:15
Swarm Source
ipfs://b098130c8be97c7dba16b56a2638cd42cb9f932ab3262f27155d40ad064ba4b2
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.