ETH Price: $2,864.80 (-2.60%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

1 address found via
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction and > 10 Token Transfers found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
217577902024-10-30 16:15:27452 days ago1730304927  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xa866BE05...14ECFC603
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Votemarket

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, BSL 1.1 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at basescan.org on 2024-10-30
*/

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.19 ^0.8.4;

// node_modules/solady/src/utils/EnumerableSetLib.sol

/// @notice Library for managing enumerable sets in storage.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EnumerableSetLib.sol)
///
/// @dev Note:
/// In many applications, the number of elements in an enumerable set is small.
/// This enumerable set implementation avoids storing the length and indices
/// for up to 3 elements. Once the length exceeds 3 for the first time, the length
/// and indices will be initialized. The amortized cost of adding elements is O(1).
///
/// The AddressSet implementation packs the length with the 0th entry.
library EnumerableSetLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The index must be less than the length.
    error IndexOutOfBounds();

    /// @dev The value cannot be the zero sentinel.
    error ValueIsZeroSentinel();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev A sentinel value to denote the zero value in storage.
    /// No elements can be equal to this value.
    /// `uint72(bytes9(keccak256(bytes("_ZERO_SENTINEL"))))`.
    uint256 private constant _ZERO_SENTINEL = 0xfbb67fda52d4bfb8bf;

    /// @dev The storage layout is given by:
    /// ```
    ///     mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED)
    ///     mstore(0x00, set.slot)
    ///     let rootSlot := keccak256(0x00, 0x24)
    ///     mstore(0x20, rootSlot)
    ///     mstore(0x00, shr(96, shl(96, value)))
    ///     let positionSlot := keccak256(0x00, 0x40)
    ///     let valueSlot := add(rootSlot, sload(positionSlot))
    ///     let valueInStorage := shr(96, sload(valueSlot))
    ///     let lazyLength := shr(160, shl(160, sload(rootSlot)))
    /// ```
    uint256 private constant _ENUMERABLE_ADDRESS_SET_SLOT_SEED = 0x978aab92;

    /// @dev The storage layout is given by:
    /// ```
    ///     mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED)
    ///     mstore(0x00, set.slot)
    ///     let rootSlot := keccak256(0x00, 0x24)
    ///     mstore(0x20, rootSlot)
    ///     mstore(0x00, value)
    ///     let positionSlot := keccak256(0x00, 0x40)
    ///     let valueSlot := add(rootSlot, sload(positionSlot))
    ///     let valueInStorage := sload(valueSlot)
    ///     let lazyLength := sload(not(rootSlot))
    /// ```
    uint256 private constant _ENUMERABLE_WORD_SET_SLOT_SEED = 0x18fb5864;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev An enumerable address set in storage.
    struct AddressSet {
        uint256 _spacer;
    }

    /// @dev An enumerable bytes32 set in storage.
    struct Bytes32Set {
        uint256 _spacer;
    }

    /// @dev An enumerable uint256 set in storage.
    struct Uint256Set {
        uint256 _spacer;
    }

    /// @dev An enumerable int256 set in storage.
    struct Int256Set {
        uint256 _spacer;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     GETTERS / SETTERS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the number of elements in the set.
    function length(AddressSet storage set) internal view returns (uint256 result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let rootPacked := sload(rootSlot)
            let n := shr(160, shl(160, rootPacked))
            result := shr(1, n)
            for {} iszero(or(iszero(shr(96, rootPacked)), n)) {} {
                result := 1
                if iszero(sload(add(rootSlot, result))) { break }
                result := 2
                if iszero(sload(add(rootSlot, result))) { break }
                result := 3
                break
            }
        }
    }

    /// @dev Returns the number of elements in the set.
    function length(Bytes32Set storage set) internal view returns (uint256 result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let n := sload(not(rootSlot))
            result := shr(1, n)
            for {} iszero(n) {} {
                result := 0
                if iszero(sload(add(rootSlot, result))) { break }
                result := 1
                if iszero(sload(add(rootSlot, result))) { break }
                result := 2
                if iszero(sload(add(rootSlot, result))) { break }
                result := 3
                break
            }
        }
    }

    /// @dev Returns the number of elements in the set.
    function length(Uint256Set storage set) internal view returns (uint256 result) {
        result = length(_toBytes32Set(set));
    }

    /// @dev Returns the number of elements in the set.
    function length(Int256Set storage set) internal view returns (uint256 result) {
        result = length(_toBytes32Set(set));
    }

    /// @dev Returns whether `value` is in the set.
    function contains(AddressSet storage set, address value) internal view returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            value := shr(96, shl(96, value))
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            let rootPacked := sload(rootSlot)
            for {} 1 {} {
                if iszero(shr(160, shl(160, rootPacked))) {
                    result := 1
                    if eq(shr(96, rootPacked), value) { break }
                    if eq(shr(96, sload(add(rootSlot, 1))), value) { break }
                    if eq(shr(96, sload(add(rootSlot, 2))), value) { break }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                result := iszero(iszero(sload(keccak256(0x00, 0x40))))
                break
            }
        }
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            for {} 1 {} {
                if iszero(sload(not(rootSlot))) {
                    result := 1
                    if eq(sload(rootSlot), value) { break }
                    if eq(sload(add(rootSlot, 1)), value) { break }
                    if eq(sload(add(rootSlot, 2)), value) { break }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                result := iszero(iszero(sload(keccak256(0x00, 0x40))))
                break
            }
        }
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Uint256Set storage set, uint256 value) internal view returns (bool result) {
        result = contains(_toBytes32Set(set), bytes32(value));
    }

    /// @dev Returns whether `value` is in the set.
    function contains(Int256Set storage set, int256 value) internal view returns (bool result) {
        result = contains(_toBytes32Set(set), bytes32(uint256(value)));
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(AddressSet storage set, address value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            value := shr(96, shl(96, value))
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            let rootPacked := sload(rootSlot)
            for { let n := shr(160, shl(160, rootPacked)) } 1 {} {
                mstore(0x20, rootSlot)
                if iszero(n) {
                    let v0 := shr(96, rootPacked)
                    if iszero(v0) {
                        sstore(rootSlot, shl(96, value))
                        result := 1
                        break
                    }
                    if eq(v0, value) { break }
                    let v1 := shr(96, sload(add(rootSlot, 1)))
                    if iszero(v1) {
                        sstore(add(rootSlot, 1), shl(96, value))
                        result := 1
                        break
                    }
                    if eq(v1, value) { break }
                    let v2 := shr(96, sload(add(rootSlot, 2)))
                    if iszero(v2) {
                        sstore(add(rootSlot, 2), shl(96, value))
                        result := 1
                        break
                    }
                    if eq(v2, value) { break }
                    mstore(0x00, v0)
                    sstore(keccak256(0x00, 0x40), 1)
                    mstore(0x00, v1)
                    sstore(keccak256(0x00, 0x40), 2)
                    mstore(0x00, v2)
                    sstore(keccak256(0x00, 0x40), 3)
                    rootPacked := or(rootPacked, 7)
                    n := 7
                }
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                if iszero(sload(p)) {
                    n := shr(1, n)
                    sstore(add(rootSlot, n), shl(96, value))
                    sstore(p, add(1, n))
                    sstore(rootSlot, add(2, rootPacked))
                    result := 1
                    break
                }
                break
            }
        }
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            for { let n := sload(not(rootSlot)) } 1 {} {
                mstore(0x20, rootSlot)
                if iszero(n) {
                    let v0 := sload(rootSlot)
                    if iszero(v0) {
                        sstore(rootSlot, value)
                        result := 1
                        break
                    }
                    if eq(v0, value) { break }
                    let v1 := sload(add(rootSlot, 1))
                    if iszero(v1) {
                        sstore(add(rootSlot, 1), value)
                        result := 1
                        break
                    }
                    if eq(v1, value) { break }
                    let v2 := sload(add(rootSlot, 2))
                    if iszero(v2) {
                        sstore(add(rootSlot, 2), value)
                        result := 1
                        break
                    }
                    if eq(v2, value) { break }
                    mstore(0x00, v0)
                    sstore(keccak256(0x00, 0x40), 1)
                    mstore(0x00, v1)
                    sstore(keccak256(0x00, 0x40), 2)
                    mstore(0x00, v2)
                    sstore(keccak256(0x00, 0x40), 3)
                    n := 7
                }
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                if iszero(sload(p)) {
                    n := shr(1, n)
                    sstore(add(rootSlot, n), value)
                    sstore(p, add(1, n))
                    sstore(not(rootSlot), or(1, shl(1, add(1, n))))
                    result := 1
                    break
                }
                break
            }
        }
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Uint256Set storage set, uint256 value) internal returns (bool result) {
        result = add(_toBytes32Set(set), bytes32(value));
    }

    /// @dev Adds `value` to the set. Returns whether `value` was not in the set.
    function add(Int256Set storage set, int256 value) internal returns (bool result) {
        result = add(_toBytes32Set(set), bytes32(uint256(value)));
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(AddressSet storage set, address value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            value := shr(96, shl(96, value))
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            let rootPacked := sload(rootSlot)
            for { let n := shr(160, shl(160, rootPacked)) } 1 {} {
                if iszero(n) {
                    result := 1
                    if eq(shr(96, rootPacked), value) {
                        sstore(rootSlot, sload(add(rootSlot, 1)))
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(shr(96, sload(add(rootSlot, 1))), value) {
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(shr(96, sload(add(rootSlot, 2))), value) {
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                let position := sload(p)
                if iszero(position) { break }
                n := sub(shr(1, n), 1)
                if iszero(eq(sub(position, 1), n)) {
                    let lastValue := shr(96, sload(add(rootSlot, n)))
                    sstore(add(rootSlot, sub(position, 1)), shl(96, lastValue))
                    sstore(add(rootSlot, n), 0)
                    mstore(0x00, lastValue)
                    sstore(keccak256(0x00, 0x40), position)
                }
                sstore(rootSlot, or(shl(96, shr(96, sload(rootSlot))), or(shl(1, n), 1)))
                sstore(p, 0)
                result := 1
                break
            }
        }
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            if eq(value, _ZERO_SENTINEL) {
                mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`.
                revert(0x1c, 0x04)
            }
            if iszero(value) { value := _ZERO_SENTINEL }
            for { let n := sload(not(rootSlot)) } 1 {} {
                if iszero(n) {
                    result := 1
                    if eq(sload(rootSlot), value) {
                        sstore(rootSlot, sload(add(rootSlot, 1)))
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(sload(add(rootSlot, 1)), value) {
                        sstore(add(rootSlot, 1), sload(add(rootSlot, 2)))
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    if eq(sload(add(rootSlot, 2)), value) {
                        sstore(add(rootSlot, 2), 0)
                        break
                    }
                    result := 0
                    break
                }
                mstore(0x20, rootSlot)
                mstore(0x00, value)
                let p := keccak256(0x00, 0x40)
                let position := sload(p)
                if iszero(position) { break }
                n := sub(shr(1, n), 1)
                if iszero(eq(sub(position, 1), n)) {
                    let lastValue := sload(add(rootSlot, n))
                    sstore(add(rootSlot, sub(position, 1)), lastValue)
                    sstore(add(rootSlot, n), 0)
                    mstore(0x00, lastValue)
                    sstore(keccak256(0x00, 0x40), position)
                }
                sstore(not(rootSlot), or(shl(1, n), 1))
                sstore(p, 0)
                result := 1
                break
            }
        }
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Uint256Set storage set, uint256 value) internal returns (bool result) {
        result = remove(_toBytes32Set(set), bytes32(value));
    }

    /// @dev Removes `value` from the set. Returns whether `value` was in the set.
    function remove(Int256Set storage set, int256 value) internal returns (bool result) {
        result = remove(_toBytes32Set(set), bytes32(uint256(value)));
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(AddressSet storage set) internal view returns (address[] memory result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let zs := _ZERO_SENTINEL
            let rootPacked := sload(rootSlot)
            let n := shr(160, shl(160, rootPacked))
            result := mload(0x40)
            let o := add(0x20, result)
            let v := shr(96, rootPacked)
            mstore(o, mul(v, iszero(eq(v, zs))))
            for {} 1 {} {
                if iszero(n) {
                    if v {
                        n := 1
                        v := shr(96, sload(add(rootSlot, n)))
                        if v {
                            n := 2
                            mstore(add(o, 0x20), mul(v, iszero(eq(v, zs))))
                            v := shr(96, sload(add(rootSlot, n)))
                            if v {
                                n := 3
                                mstore(add(o, 0x40), mul(v, iszero(eq(v, zs))))
                            }
                        }
                    }
                    break
                }
                n := shr(1, n)
                for { let i := 1 } lt(i, n) { i := add(i, 1) } {
                    v := shr(96, sload(add(rootSlot, i)))
                    mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs))))
                }
                break
            }
            mstore(result, n)
            mstore(0x40, add(o, shl(5, n)))
        }
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            let zs := _ZERO_SENTINEL
            let n := sload(not(rootSlot))
            result := mload(0x40)
            let o := add(0x20, result)
            for {} 1 {} {
                if iszero(n) {
                    let v := sload(rootSlot)
                    if v {
                        n := 1
                        mstore(o, mul(v, iszero(eq(v, zs))))
                        v := sload(add(rootSlot, n))
                        if v {
                            n := 2
                            mstore(add(o, 0x20), mul(v, iszero(eq(v, zs))))
                            v := sload(add(rootSlot, n))
                            if v {
                                n := 3
                                mstore(add(o, 0x40), mul(v, iszero(eq(v, zs))))
                            }
                        }
                    }
                    break
                }
                n := shr(1, n)
                for { let i := 0 } lt(i, n) { i := add(i, 1) } {
                    let v := sload(add(rootSlot, i))
                    mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs))))
                }
                break
            }
            mstore(result, n)
            mstore(0x40, add(o, shl(5, n)))
        }
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(Uint256Set storage set) internal view returns (uint256[] memory result) {
        result = _toUints(values(_toBytes32Set(set)));
    }

    /// @dev Returns all of the values in the set.
    /// Note: This can consume more gas than the block gas limit for large sets.
    function values(Int256Set storage set) internal view returns (int256[] memory result) {
        result = _toInts(values(_toBytes32Set(set)));
    }

    /// @dev Returns the element at index `i` in the set.
    function at(AddressSet storage set, uint256 i) internal view returns (address result) {
        bytes32 rootSlot = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            result := shr(96, sload(add(rootSlot, i)))
            result := mul(result, iszero(eq(result, _ZERO_SENTINEL)))
        }
        if (i >= length(set)) revert IndexOutOfBounds();
    }

    /// @dev Returns the element at index `i` in the set.
    function at(Bytes32Set storage set, uint256 i) internal view returns (bytes32 result) {
        result = _rootSlot(set);
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(add(result, i))
            result := mul(result, iszero(eq(result, _ZERO_SENTINEL)))
        }
        if (i >= length(set)) revert IndexOutOfBounds();
    }

    /// @dev Returns the element at index `i` in the set.
    function at(Uint256Set storage set, uint256 i) internal view returns (uint256 result) {
        result = uint256(at(_toBytes32Set(set), i));
    }

    /// @dev Returns the element at index `i` in the set.
    function at(Int256Set storage set, uint256 i) internal view returns (int256 result) {
        result = int256(uint256(at(_toBytes32Set(set), i)));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the root slot.
    function _rootSlot(AddressSet storage s) private pure returns (bytes32 r) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED)
            mstore(0x00, s.slot)
            r := keccak256(0x00, 0x24)
        }
    }

    /// @dev Returns the root slot.
    function _rootSlot(Bytes32Set storage s) private pure returns (bytes32 r) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED)
            mstore(0x00, s.slot)
            r := keccak256(0x00, 0x24)
        }
    }

    /// @dev Casts to a Bytes32Set.
    function _toBytes32Set(Uint256Set storage s) private pure returns (Bytes32Set storage c) {
        /// @solidity memory-safe-assembly
        assembly {
            c.slot := s.slot
        }
    }

    /// @dev Casts to a Bytes32Set.
    function _toBytes32Set(Int256Set storage s) private pure returns (Bytes32Set storage c) {
        /// @solidity memory-safe-assembly
        assembly {
            c.slot := s.slot
        }
    }

    /// @dev Casts to a uint256 array.
    function _toUints(bytes32[] memory a) private pure returns (uint256[] memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := a
        }
    }

    /// @dev Casts to a int256 array.
    function _toInts(bytes32[] memory a) private pure returns (int256[] memory c) {
        /// @solidity memory-safe-assembly
        assembly {
            c := a
        }
    }
}

// node_modules/solady/src/utils/FixedPointMathLib.sol

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error ExpOverflow();

    /// @dev The operation failed, as the output exceeds the maximum value of uint256.
    error FactorialOverflow();

    /// @dev The operation failed, due to an overflow.
    error RPowOverflow();

    /// @dev The mantissa is too big to fit.
    error MantissaOverflow();

    /// @dev The operation failed, due to an multiplication overflow.
    error MulWadFailed();

    /// @dev The operation failed, due to an multiplication overflow.
    error SMulWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error DivWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error SDivWadFailed();

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The division failed, as the denominator is zero.
    error DivFailed();

    /// @dev The full precision multiply-divide operation failed, either due
    /// to the result being larger than 256 bits, or a division by a zero.
    error FullMulDivFailed();

    /// @dev The output is undefined, as the input is less-than-or-equal to zero.
    error LnWadUndefined();

    /// @dev The input outside the acceptable domain.
    error OutOfDomain();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              SIMPLIFIED FIXED POINT OPERATIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down.
    function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
            if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
                mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := sdiv(z, WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
    function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
    function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(mul(x, y), WAD)
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up.
    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
            if mul(y, gt(x, div(not(0), y))) {
                mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
    function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down.
    function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, WAD)
            // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
            if iszero(and(iszero(iszero(y)), eq(sdiv(z, WAD), x))) {
                mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := sdiv(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
    function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
    function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(mul(x, WAD), y)
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up.
    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to `require(y != 0 && (WAD == 0 || x <= type(uint256).max / WAD))`.
            if iszero(mul(y, iszero(mul(WAD, gt(x, div(not(0), WAD)))))) {
                mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
    function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
        }
    }

    /// @dev Equivalent to `x` to the power of `y`.
    /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
    /// Note: This function is an approximation.
    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Using `ln(x)` means `x` must be greater than 0.
        return expWad((lnWad(x) * y) / int256(WAD));
    }

    /// @dev Returns `exp(x)`, denominated in `WAD`.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
    /// Note: This function is an approximation. Monotonically increasing.
    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is less than 0.5 we return zero.
            // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
            if (x <= -41446531673892822313) return r;

            /// @solidity memory-safe-assembly
            assembly {
                // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
                // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
                if iszero(slt(x, 135305999368893231589)) {
                    mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
                    revert(0x1c, 0x04)
                }
            }

            // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5 ** 18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // `k` is in the range `[-61, 195]`.

            // Evaluate using a (6, 7)-term rational approximation.
            // `p` is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            /// @solidity memory-safe-assembly
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already `2**96` too large.
                r := sdiv(p, q)
            }

            // r should be in the range `(0.09, 0.25) * 2**96`.

            // We now need to multiply r by:
            // - The scale factor `s ≈ 6.031367120`.
            // - The `2**k` factor from the range reduction.
            // - The `1e18 / 2**96` factor for base conversion.
            // We do this all at once, with an intermediate result in `2**213`
            // basis, so the final right shift is always by a positive amount.
            r = int256(
                (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
            );
        }
    }

    /// @dev Returns `ln(x)`, denominated in `WAD`.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
    /// Note: This function is an approximation. Monotonically increasing.
    function lnWad(int256 x) internal pure returns (int256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
            // We do this by multiplying by `2**96 / 10**18`. But since
            // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
            // and add `ln(2**96 / 10**18)` at the end.

            // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // We place the check here for more optimal stack operations.
            if iszero(sgt(x, 0)) {
                mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
                revert(0x1c, 0x04)
            }
            // forgefmt: disable-next-item
            r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            x := shr(159, shl(r, x))

            // Evaluate using a (8, 8)-term rational approximation.
            // `p` is made monic, we will multiply by a scale factor later.
            // forgefmt: disable-next-item
            let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
                sar(96, mul(add(43456485725739037958740375743393,
                sar(96, mul(add(24828157081833163892658089445524,
                sar(96, mul(add(3273285459638523848632254066296,
                    x), x))), x))), x)), 11111509109440967052023855526967)
            p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
            p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
            p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
            // We leave `p` in `2**192` basis so we don't need to scale it back up for the division.

            // `q` is monic by convention.
            let q := add(5573035233440673466300451813936, x)
            q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
            q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
            q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
            q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
            q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
            q := add(909429971244387300277376558375, sar(96, mul(x, q)))

            // `p / q` is in the range `(0, 0.125) * 2**96`.

            // Finalization, we need to:
            // - Multiply by the scale factor `s = 5.549…`.
            // - Add `ln(2**96 / 10**18)`.
            // - Add `k * ln(2)`.
            // - Multiply by `10**18 / 2**96 = 5**18 >> 78`.

            // The q polynomial is known not to have zeros in the domain.
            // No scaling required because p is already `2**96` too large.
            p := sdiv(p, q)
            // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
            p := mul(1677202110996718588342820967067443963516166, p)
            // Add `ln(2) * k * 5**18 * 2**192`.
            // forgefmt: disable-next-item
            p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
            // Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
            p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
            // Base conversion: mul `2**18 / 2**192`.
            r := sar(174, p)
        }
    }

    /// @dev Returns `W_0(x)`, denominated in `WAD`.
    /// See: https://en.wikipedia.org/wiki/Lambert_W_function
    /// a.k.a. Product log function. This is an approximation of the principal branch.
    /// Note: This function is an approximation. Monotonically increasing.
    function lambertW0Wad(int256 x) internal pure returns (int256 w) {
        // forgefmt: disable-next-item
        unchecked {
            if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
            int256 wad = int256(WAD);
            int256 p = x;
            uint256 c; // Whether we need to avoid catastrophic cancellation.
            uint256 i = 4; // Number of iterations.
            if (w <= 0x1ffffffffffff) {
                if (-0x4000000000000 <= w) {
                    i = 1; // Inputs near zero only take one step to converge.
                } else if (w <= -0x3ffffffffffffff) {
                    i = 32; // Inputs near `-1/e` take very long to converge.
                }
            } else if (uint256(w >> 63) == uint256(0)) {
                /// @solidity memory-safe-assembly
                assembly {
                    // Inline log2 for more performance, since the range is small.
                    let v := shr(49, w)
                    let l := shl(3, lt(0xff, v))
                    l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
                        0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
                    w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
                    c := gt(l, 60)
                    i := add(2, add(gt(l, 53), c))
                }
            } else {
                int256 ll = lnWad(w = lnWad(w));
                /// @solidity memory-safe-assembly
                assembly {
                    // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
                    w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
                    i := add(3, iszero(shr(68, x)))
                    c := iszero(shr(143, x))
                }
                if (c == uint256(0)) {
                    do { // If `x` is big, use Newton's so that intermediate values won't overflow.
                        int256 e = expWad(w);
                        /// @solidity memory-safe-assembly
                        assembly {
                            let t := mul(w, div(e, wad))
                            w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
                        }
                        if (p <= w) break;
                        p = w;
                    } while (--i != uint256(0));
                    /// @solidity memory-safe-assembly
                    assembly {
                        w := sub(w, sgt(w, 2))
                    }
                    return w;
                }
            }
            do { // Otherwise, use Halley's for faster convergence.
                int256 e = expWad(w);
                /// @solidity memory-safe-assembly
                assembly {
                    let t := add(w, wad)
                    let s := sub(mul(w, e), mul(x, wad))
                    w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
                }
                if (p <= w) break;
                p = w;
            } while (--i != c);
            /// @solidity memory-safe-assembly
            assembly {
                w := sub(w, sgt(w, 2))
            }
            // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
            // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
            if (c == uint256(0)) return w;
            int256 t = w | 1;
            /// @solidity memory-safe-assembly
            assembly {
                x := sdiv(mul(x, wad), t)
            }
            x = (t * (wad + lnWad(x)));
            /// @solidity memory-safe-assembly
            assembly {
                w := sdiv(x, add(wad, t))
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // 512-bit multiply `[p1 p0] = x * y`.
            // Compute the product mod `2**256` and mod `2**256 - 1`
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that `product = p1 * 2**256 + p0`.

            // Temporarily use `result` as `p0` to save gas.
            result := mul(x, y) // Lower 256 bits of `x * y`.
            for {} 1 {} {
                // If overflows.
                if iszero(mul(or(iszero(x), eq(div(result, x), y)), d)) {
                    let mm := mulmod(x, y, not(0))
                    let p1 := sub(mm, add(result, lt(mm, result))) // Upper 256 bits of `x * y`.

                    /*------------------- 512 by 256 division --------------------*/

                    // Make division exact by subtracting the remainder from `[p1 p0]`.
                    let r := mulmod(x, y, d) // Compute remainder using mulmod.
                    let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
                    // Make sure the result is less than `2**256`. Also prevents `d == 0`.
                    // Placing the check here seems to give more optimal stack operations.
                    if iszero(gt(d, p1)) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    d := div(d, t) // Divide `d` by `t`, which is a power of two.
                    // Invert `d mod 2**256`
                    // Now that `d` is an odd number, it has an inverse
                    // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                    // Compute the inverse by starting with a seed that is correct
                    // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                    let inv := xor(2, mul(3, d))
                    // Now use Newton-Raphson iteration to improve the precision.
                    // Thanks to Hensel's lifting lemma, this also works in modular
                    // arithmetic, doubling the correct bits in each step.
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                    inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                    result :=
                        mul(
                            // Divide [p1 p0] by the factors of two.
                            // Shift in bits from `p1` into `p0`. For this we need
                            // to flip `t` such that it is `2**256 / t`.
                            or(
                                mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
                                div(sub(result, r), t)
                            ),
                            mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
                        )
                    break
                }
                result := div(result, d)
                break
            }
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
    /// Performs the full 512 bit calculation regardless.
    function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := mul(x, y)
            let mm := mulmod(x, y, not(0))
            let p1 := sub(mm, add(result, lt(mm, result)))
            let t := and(d, sub(0, d))
            let r := mulmod(x, y, d)
            d := div(d, t)
            let inv := xor(2, mul(3, d))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            inv := mul(inv, sub(2, mul(d, inv)))
            result :=
                mul(
                    or(mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)), div(sub(result, r), t)),
                    mul(sub(2, mul(d, inv)), inv)
                )
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Uniswap-v3-core under MIT license:
    /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        result = fullMulDiv(x, y, d);
        /// @solidity memory-safe-assembly
        assembly {
            if mulmod(x, y, d) {
                result := add(result, 1)
                if iszero(result) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Returns `floor(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
            if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(z, d)
        }
    }

    /// @dev Returns `ceil(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(x, y)
            // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
            if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(z, d))), div(z, d))
        }
    }

    /// @dev Returns `ceil(x / d)`.
    /// Reverts if `d` is zero.
    function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(d) {
                mstore(0x00, 0x65244e4e) // `DivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(x, d))), div(x, d))
        }
    }

    /// @dev Returns `max(0, x - y)`.
    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Returns `condition ? x : y`, without branching.
    function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := xor(x, mul(xor(x, y), iszero(condition)))
        }
    }

    /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
    /// Reverts if the computation overflows.
    function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
            if x {
                z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
                let half := shr(1, b) // Divide `b` by 2.
                // Divide `y` by 2 every iteration.
                for { y := shr(1, y) } y { y := shr(1, y) } {
                    let xx := mul(x, x) // Store x squared.
                    let xxRound := add(xx, half) // Round to the nearest number.
                    // Revert if `xx + half` overflowed, or if `x ** 2` overflows.
                    if or(lt(xxRound, xx), shr(128, x)) {
                        mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                        revert(0x1c, 0x04)
                    }
                    x := div(xxRound, b) // Set `x` to scaled `xxRound`.
                    // If `y` is odd:
                    if and(y, 1) {
                        let zx := mul(z, x) // Compute `z * x`.
                        let zxRound := add(zx, half) // Round to the nearest number.
                        // If `z * x` overflowed or `zx + half` overflowed:
                        if or(xor(div(zx, x), z), lt(zxRound, zx)) {
                            // Revert if `x` is non-zero.
                            if x {
                                mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
                                revert(0x1c, 0x04)
                            }
                        }
                        z := div(zxRound, b) // Return properly scaled `zxRound`.
                    }
                }
            }
        }
    }

    /// @dev Returns the square root of `x`, rounded down.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            z := sub(z, lt(div(x, z), z))
        }
    }

    /// @dev Returns the cube root of `x`, rounded down.
    /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
    /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
    function cbrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))

            z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))

            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)
            z := div(add(add(div(x, mul(z, z)), z), z), 3)

            z := sub(z, lt(div(x, mul(z, z)), z))
        }
    }

    /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
    function sqrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
            z = (1 + sqrt(x)) * 10 ** 9;
            z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
        }
        /// @solidity memory-safe-assembly
        assembly {
            z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1)))
        }
    }

    /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
    function cbrtWad(uint256 x) internal pure returns (uint256 z) {
        unchecked {
            if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
            z = (1 + cbrt(x)) * 10 ** 12;
            z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
            x = fullMulDivUnchecked(x, 10 ** 36, z * z);
        }
        /// @solidity memory-safe-assembly
        assembly {
            z := sub(z, lt(x, z))
        }
    }

    /// @dev Returns the factorial of `x`.
    function factorial(uint256 x) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(x, 58)) {
                mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
                revert(0x1c, 0x04)
            }
            for {} x { x := sub(x, 1) } { result := mul(result, x) }
        }
    }

    /// @dev Returns the log2 of `x`.
    /// Equivalent to computing the index of the most significant bit (MSB) of `x`.
    /// Returns 0 if `x` is zero.
    function log2(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            // forgefmt: disable-next-item
            r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
                0x0706060506020504060203020504030106050205030304010505030400000000))
        }
    }

    /// @dev Returns the log2 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log2Up(uint256 x) internal pure returns (uint256 r) {
        r = log2(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(r, 1), x))
        }
    }

    /// @dev Returns the log10 of `x`.
    /// Returns 0 if `x` is zero.
    function log10(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(x, 100000000000000000000000000000000000000)) {
                x := div(x, 100000000000000000000000000000000000000)
                r := 38
            }
            if iszero(lt(x, 100000000000000000000)) {
                x := div(x, 100000000000000000000)
                r := add(r, 20)
            }
            if iszero(lt(x, 10000000000)) {
                x := div(x, 10000000000)
                r := add(r, 10)
            }
            if iszero(lt(x, 100000)) {
                x := div(x, 100000)
                r := add(r, 5)
            }
            r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
        }
    }

    /// @dev Returns the log10 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log10Up(uint256 x) internal pure returns (uint256 r) {
        r = log10(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(exp(10, r), x))
        }
    }

    /// @dev Returns the log256 of `x`.
    /// Returns 0 if `x` is zero.
    function log256(uint256 x) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(shr(3, r), lt(0xff, shr(r, x)))
        }
    }

    /// @dev Returns the log256 of `x`, rounded up.
    /// Returns 0 if `x` is zero.
    function log256Up(uint256 x) internal pure returns (uint256 r) {
        r = log256(x);
        /// @solidity memory-safe-assembly
        assembly {
            r := add(r, lt(shl(shl(3, r), 1), x))
        }
    }

    /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
    /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
    function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
        /// @solidity memory-safe-assembly
        assembly {
            mantissa := x
            if mantissa {
                if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
                    mantissa := div(mantissa, 1000000000000000000000000000000000)
                    exponent := 33
                }
                if iszero(mod(mantissa, 10000000000000000000)) {
                    mantissa := div(mantissa, 10000000000000000000)
                    exponent := add(exponent, 19)
                }
                if iszero(mod(mantissa, 1000000000000)) {
                    mantissa := div(mantissa, 1000000000000)
                    exponent := add(exponent, 12)
                }
                if iszero(mod(mantissa, 1000000)) {
                    mantissa := div(mantissa, 1000000)
                    exponent := add(exponent, 6)
                }
                if iszero(mod(mantissa, 10000)) {
                    mantissa := div(mantissa, 10000)
                    exponent := add(exponent, 4)
                }
                if iszero(mod(mantissa, 100)) {
                    mantissa := div(mantissa, 100)
                    exponent := add(exponent, 2)
                }
                if iszero(mod(mantissa, 10)) {
                    mantissa := div(mantissa, 10)
                    exponent := add(exponent, 1)
                }
            }
        }
    }

    /// @dev Convenience function for packing `x` into a smaller number using `sci`.
    /// The `mantissa` will be in bits [7..255] (the upper 249 bits).
    /// The `exponent` will be in bits [0..6] (the lower 7 bits).
    /// Use `SafeCastLib` to safely ensure that the `packed` number is small
    /// enough to fit in the desired unsigned integer type:
    /// ```
    ///     uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
    /// ```
    function packSci(uint256 x) internal pure returns (uint256 packed) {
        (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
        /// @solidity memory-safe-assembly
        assembly {
            if shr(249, x) {
                mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
                revert(0x1c, 0x04)
            }
            packed := or(shl(7, x), packed)
        }
    }

    /// @dev Convenience function for unpacking a packed number from `packSci`.
    function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
        unchecked {
            unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
        }
    }

    /// @dev Returns the average of `x` and `y`. Rounds towards zero.
    function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = (x & y) + ((x ^ y) >> 1);
        }
    }

    /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
    function avg(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = (x >> 1) + (y >> 1) + (x & y & 1);
        }
    }

    /// @dev Returns the absolute value of `x`.
    function abs(int256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(sar(255, x), add(sar(255, x), x))
        }
    }

    /// @dev Returns the absolute distance between `x` and `y`.
    function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(mul(xor(sub(y, x), sub(x, y)), gt(x, y)), sub(y, x))
        }
    }

    /// @dev Returns the absolute distance between `x` and `y`.
    function dist(int256 x, int256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(mul(xor(sub(y, x), sub(x, y)), sgt(x, y)), sub(y, x))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }

    /// @dev Returns the minimum of `x` and `y`.
    function min(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), slt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), gt(y, x)))
        }
    }

    /// @dev Returns the maximum of `x` and `y`.
    function max(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, y), sgt(y, x)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(uint256 x, uint256 minValue, uint256 maxValue)
        internal
        pure
        returns (uint256 z)
    {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
        }
    }

    /// @dev Returns `x`, bounded to `minValue` and `maxValue`.
    function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
            z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
        }
    }

    /// @dev Returns greatest common divisor of `x` and `y`.
    function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            for { z := x } y {} {
                let t := y
                y := mod(z, y)
                z := t
            }
        }
    }

    /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
    /// with `t` clamped between `begin` and `end` (inclusive).
    /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
    /// If `begins == end`, returns `t <= begin ? a : b`.
    function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
        internal
        pure
        returns (uint256)
    {
        if (begin > end) {
            t = ~t;
            begin = ~begin;
            end = ~end;
        }
        if (t <= begin) return a;
        if (t >= end) return b;
        unchecked {
            if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
            return a - fullMulDiv(a - b, t - begin, end - begin);
        }
    }

    /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
    /// with `t` clamped between `begin` and `end` (inclusive).
    /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
    /// If `begins == end`, returns `t <= begin ? a : b`.
    function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
        internal
        pure
        returns (int256)
    {
        if (begin > end) {
            t = int256(~uint256(t));
            begin = int256(~uint256(begin));
            end = int256(~uint256(end));
        }
        if (t <= begin) return a;
        if (t >= end) return b;
        // forgefmt: disable-next-item
        unchecked {
            if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b) - uint256(a),
                uint256(t) - uint256(begin), uint256(end) - uint256(begin)));
            return int256(uint256(a) - fullMulDiv(uint256(a) - uint256(b),
                uint256(t) - uint256(begin), uint256(end) - uint256(begin)));
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   RAW NUMBER OPERATIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x + y`, without checking for overflow.
    function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x + y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x - y`, without checking for underflow.
    function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x - y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x * y`, without checking for overflow.
    function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
        unchecked {
            z = x * y;
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(x, y)
        }
    }

    /// @dev Returns `x / y`, returning 0 if `y` is zero.
    function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := sdiv(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mod(x, y)
        }
    }

    /// @dev Returns `x % y`, returning 0 if `y` is zero.
    function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := smod(x, y)
        }
    }

    /// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
    function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := addmod(x, y, d)
        }
    }

    /// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
    function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mulmod(x, y, d)
        }
    }
}

// node_modules/solady/src/utils/ReentrancyGuard.sol

/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
    /// 9 bytes is large enough to avoid collisions with lower slots,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      REENTRANCY GUARD                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            sstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            sstore(_REENTRANCY_GUARD_SLOT, codesize())
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

// node_modules/solady/src/utils/SafeTransferLib.sol

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success :=
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `1` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

// src/interfaces/IHook.sol

interface IHook {
    function validateHook() external view returns (bool);
    function doSomething(
        uint256 campaignId,
        uint256 chainId,
        address rewardToken,
        uint256 epoch,
        uint256 amount,
        bytes calldata hookData
    ) external;

    function returnFunds(address token, address to, uint256 amount) external;
}

// src/interfaces/IOracleLens.sol

interface IOracleLens {
    function isVoteValid(address account, address gauge, uint256 epoch) external view returns (bool);
    function getTotalVotes(address gauge, uint256 epoch) external view returns (uint256);
    function getAccountVotes(address account, address gauge, uint256 epoch) external view returns (uint256);
}

// src/interfaces/IVotemarket.sol

////////////////////////////////////////////////////////////////
/// --- DATA STRUCTURE DEFINITIONS
///////////////////////////////////////////////////////////////

struct Campaign {
    /// @notice Chain Id of the destination chain where the gauge is deployed.
    uint256 chainId;
    /// @notice Destination gauge address.
    address gauge;
    /// @notice Address to manage the campaign.
    address manager;
    /// @notice Main reward token.
    address rewardToken;
    /// @notice Duration of the campaign in weeks.
    uint8 numberOfPeriods;
    /// @notice Maximum reward per vote to distribute, to avoid overspending.
    uint256 maxRewardPerVote;
    /// @notice Total reward amount to distribute.
    uint256 totalRewardAmount;
    /// @notice Total reward amount distributed.
    uint256 totalDistributed;
    /// @notice Start timestamp of the campaign.
    uint256 startTimestamp;
    /// @notice End timestamp of the campaign.
    uint256 endTimestamp;
    /// Hook address.
    address hook;
}

/// @notice Claim data struct to avoid stack too deep errors.
struct ClaimData {
    /// @notice Campaign ID.
    uint256 campaignId;
    /// @notice Account address.
    address account;
    /// @notice Receiver address.
    address receiver;
    /// @notice Epoch to claim.
    uint256 epoch;
    /// @notice Amount to claim.
    uint256 amountToClaim;
    /// @notice Fee amount.
    uint256 feeAmount;
}

struct Period {
    /// @notice Amount of reward reserved for the period.
    uint256 rewardPerPeriod;
    /// @notice Reward Per Vote.
    uint256 rewardPerVote;
    /// @notice  Leftover amount.
    uint256 leftover;
    /// @notice Flag to indicate if the period is updated.
    bool updated;
}

struct CampaignUpgrade {
    /// @notice Number of periods after increase.
    uint8 numberOfPeriods;
    /// @notice Total reward amount after increase.
    uint256 totalRewardAmount;
    /// @notice New max reward per vote after increase.
    uint256 maxRewardPerVote;
    /// @notice New end timestamp after increase.
    uint256 endTimestamp;
}

interface IVotemarket {
    function createCampaign(
        uint256 chainId,
        address gauge,
        address manager,
        address rewardToken,
        uint8 numberOfPeriods,
        uint256 maxRewardPerVote,
        uint256 totalRewardAmount,
        address[] memory addresses,
        address hook,
        bool whitelist
    ) external returns (uint256 campaignId);

    function manageCampaign(
        uint256 campaignId,
        uint8 numberOfPeriods,
        uint256 totalRewardAmount,
        uint256 maxRewardPerVote
    ) external;

    function getCampaign(uint256 campaignId) external view returns (Campaign memory);

    function claim(uint256 campaignId, address account, uint256 epoch, bytes calldata hookData)
        external
        returns (uint256 claimed);

    function updateEpoch(uint256 campaignId, uint256 epoch, bytes calldata hookData) external;
}

// src/Votemarket.sol

/// External Libraries

/// Project Interfaces & Libraries

/// @notice Vote market contract.
/// Next iteration of the Votemarket contract. This contract is designed to store the state of each campaign and allow the claim at any point in time.
/// It uses storage proofs to validate and verify the votes and distribute the rewards accordingly.
/// @dev This contract is better suited for L2s. Unadvised to deploy on L1.
/// @custom:contact [email protected]
contract Votemarket is ReentrancyGuard {
    using FixedPointMathLib for uint256;
    using EnumerableSetLib for EnumerableSetLib.AddressSet;

    ////////////////////////////////////////////////////////////////
    /// --- CONSTANT VALUES
    ///////////////////////////////////////////////////////////////

    /// @notice Claim window length in seconds.
    /// 6 months.
    uint256 public constant CLAIM_WINDOW_LENGTH = 24 weeks;

    /// @notice Close window length in seconds.
    /// 1 month.
    uint256 public constant CLOSE_WINDOW_LENGTH = 4 weeks;

    /// @notice Maximum number of addresses per campaign.
    uint256 public constant MAX_ADDRESSES_PER_CAMPAIGN = 50;

    /// @notice Minimum duration for a campaign.
    uint8 public immutable MINIMUM_PERIODS;

    /// @notice Epoch length in seconds.
    uint256 public immutable EPOCH_LENGTH;

    /// @notice Oracle address.
    address public immutable ORACLE;

    ////////////////////////////////////////////////////////////////
    /// --- STORAGE VARIABLES
    ///////////////////////////////////////////////////////////////

    /// @notice Governance address.
    address public governance;

    /// @notice Future governance address.
    address public futureGovernance;

    /// @notice Address of the remote cross-chain message handler.
    address public remote;

    /// @notice Fee receiver.
    address public feeCollector;

    /// @notice Fee.
    uint256 public fee;

    /// @notice Campaigns count.
    uint256 public campaignCount;

    /// @notice Protected addresses.
    /// @dev Smart Contracts addresses that cannot set recipients by themselves, or didn't manage to replicate the address on L2.
    /// Example: Yearn yCRV Locker, Convex VoterProxy, StakeDAO Locker.
    mapping(address => bool) public isProtected;

    /// @notice Recipients.
    mapping(address => address) public recipients;

    /// @notice Custom fee per manager.
    mapping(address => uint256) public customFeeByManager;

    /// @notice Campaigns by Id.
    mapping(uint256 => Campaign) public campaignById;

    /// @notice If campaign is closed.
    mapping(uint256 => bool) public isClosedCampaign;

    /// @notice Periods by campaign Id and Epoch.
    mapping(uint256 => mapping(uint256 => Period)) public periodByCampaignId;

    /// @notice Campaign Upgrades in queue by Id. To be applied at the next action. (claim, upgrade)
    mapping(uint256 => mapping(uint256 => CampaignUpgrade)) public campaignUpgradeById;

    /// @notice Total claimed per campaign Id.
    mapping(uint256 => uint256) public totalClaimedByCampaignId;

    /// @notice Total claimed per user per campaign Id and period Id.
    mapping(uint256 => mapping(uint256 => mapping(address => uint256))) public totalClaimedByAccount;

    /// @notice Mapping of campaign ids that are whitelist only.
    mapping(uint256 => bool) public whitelistOnly;

    /// @notice Set of addresses that are whitelisted / blacklisted.
    mapping(uint256 => EnumerableSetLib.AddressSet) public addressesByCampaignId;

    ////////////////////////////////////////////////////////////////
    /// ---  EVENTS & ERRORS
    ///////////////////////////////////////////////////////////////

    /// @notice Thrown when a zero value is provided where a non-zero value is required.
    error ZERO_INPUT();

    /// @notice Thrown when a zero address is provided where a non-zero address is required.
    error ZERO_ADDRESS();

    /// @notice Thrown when an invalid token address is provided.
    error INVALID_TOKEN();

    /// @notice Thrown when an input parameter is invalid.
    error INVALID_INPUT();

    /// @notice Thrown when a claim is made for an account that is protected.
    error PROTECTED_ACCOUNT();

    /// @notice Thrown when the previous state of a campaign is missing.
    error STATE_MISSING();

    /// @notice Thrown when a claim amount exceeds the available reward amount.
    error CLAIM_AMOUNT_EXCEEDS_REWARD_AMOUNT();

    /// @notice Thrown when attempting to interact with an ended campaign.
    error CAMPAIGN_ENDED();

    /// @notice Thrown when attempting to close a campaign that has not ended.
    error CAMPAIGN_NOT_ENDED();

    /// @notice Thrown when an invalid epoch is provided.
    error EPOCH_NOT_VALID();

    /// @notice Thrown when a blacklisted address attempts an unauthorized action.
    error AUTH_BLACKLISTED();

    /// @notice Thrown when a non-manager attempts a manager-only action.
    error AUTH_MANAGER_ONLY();

    /// @notice Thrown when a non-whitelisted address attempts an action in a whitelist-only campaign.
    error AUTH_WHITELIST_ONLY();

    /// @notice Thrown when a non-governance address attempts a governance-only action.
    error AUTH_GOVERNANCE_ONLY();

    /// @notice Emitted when a claim is made.
    event Claim(uint256 indexed campaignId, address indexed account, uint256 amount, uint256 fee, uint256 epoch);

    /// @notice Emitted when a new campaign is created.
    event CampaignCreated(
        uint256 campaignId,
        address gauge,
        address manager,
        address rewardToken,
        uint8 numberOfPeriods,
        uint256 maxRewardPerVote,
        uint256 totalRewardAmount
    );

    /// @notice Emitted when a campaign upgrade is queued.
    event CampaignUpgradeQueued(uint256 campaignId, uint256 epoch);

    /// @notice Emitted when a campaign is upgraded.
    event CampaignUpgraded(uint256 campaignId, uint256 epoch);

    /// @notice Emitted when a campaign is closed.
    event CampaignClosed(uint256 campaignId);

    ////////////////////////////////////////////////////////////////
    /// --- MODIFIERS
    ///////////////////////////////////////////////////////////////

    /// @notice Ensures that only the governance address can call the function.
    modifier onlyGovernance() {
        if (msg.sender != governance) revert AUTH_GOVERNANCE_ONLY();
        _;
    }

    /// @notice Checks if an account is whitelisted or blacklisted for a campaign.
    modifier checkWhitelistOrBlacklist(uint256 campaignId, address account, uint256 epoch) {
        bool contains = addressesByCampaignId[campaignId].contains(account);
        if (whitelistOnly[campaignId] && !contains) {
            revert AUTH_WHITELIST_ONLY();
        } else if (!whitelistOnly[campaignId] && contains) {
            revert AUTH_BLACKLISTED();
        }
        _;
    }

    /// @notice Ensures that the provided epoch is valid for the given campaign.
    modifier validEpoch(uint256 campaignId, uint256 epoch) {
        if (
            epoch > block.timestamp || epoch < campaignById[campaignId].startTimestamp
                || epoch >= campaignById[campaignId].endTimestamp || epoch % EPOCH_LENGTH != 0
        ) revert EPOCH_NOT_VALID();
        _;
    }

    /// @notice Ensures that the campaign is not closed.
    modifier notClosed(uint256 campaignId) {
        if (isClosedCampaign[campaignId]) revert CAMPAIGN_ENDED();
        _;
    }

    /// @notice Ensures that only the campaign manager or remote address can call the function.
    modifier onlyManagerOrRemote(uint256 campaignId) {
        _isManagerOrRemote(campaignId);
        _;
    }

    /// @notice Check if the manager or remote is calling the function.
    /// @param campaignId The ID of the campaign.
    function _isManagerOrRemote(uint256 campaignId) internal view {
        if (msg.sender != campaignById[campaignId].manager && msg.sender != remote) revert AUTH_MANAGER_ONLY();
    }

    /// @notice Contract constructor.
    /// @param _governance The address of the governance.
    /// @param _oracle The address of the oracle.
    /// @param _feeCollector The address of the fee collector.
    /// @param _epochLength The length of an epoch in seconds.
    /// @param _minimumPeriods The minimum number of periods for a campaign.
    constructor(
        address _governance,
        address _oracle,
        address _feeCollector,
        uint256 _epochLength,
        uint8 _minimumPeriods
    ) {
        governance = _governance;
        feeCollector = _feeCollector;

        /// Default fee is 4%.
        fee = 4e16;

        ORACLE = _oracle;
        EPOCH_LENGTH = _epochLength;
        MINIMUM_PERIODS = _minimumPeriods;
    }

    ////////////////////////////////////////////////////////////////
    /// --- CLAIM LOGIC
    ///////////////////////////////////////////////////////////////

    /// @notice Allows claiming rewards for a specified account.
    /// @param campaignId The ID of the campaign.
    /// @param account The account to claim for.
    /// @param epoch The epoch to claim for.
    /// @param hookData Additional data for hooks.
    /// @return claimed The amount of rewards claimed.
    function claim(uint256 campaignId, address account, uint256 epoch, bytes calldata hookData)
        external
        nonReentrant
        returns (uint256 claimed)
    {
        /// 1. Check if the account is protected.
        if (isProtected[account] && recipients[account] == address(0)) revert PROTECTED_ACCOUNT();

        /// 2. Set the receiver.
        address receiver = recipients[account] == address(0) ? account : recipients[account];

        return _claim(
            ClaimData({
                campaignId: campaignId,
                account: account,
                receiver: receiver,
                epoch: epoch,
                amountToClaim: 0,
                feeAmount: 0
            }),
            hookData
        );
    }

    /// @notice Allows a user to claim rewards for a campaign.
    /// @param campaignId The ID of the campaign.
    /// @param receiver The address to receive the rewards.
    /// @param epoch The epoch for which to claim rewards.
    /// @param hookData Additional data for hooks.
    /// @return claimed The amount of rewards claimed.
    function claim(uint256 campaignId, uint256 epoch, bytes calldata hookData, address receiver)
        external
        nonReentrant
        returns (uint256 claimed)
    {
        return _claim(
            ClaimData({
                campaignId: campaignId,
                account: msg.sender,
                receiver: receiver,
                epoch: epoch,
                amountToClaim: 0,
                feeAmount: 0
            }),
            hookData
        );
    }

    /// @notice Internal function to process a claim.
    /// @param data The claim data.
    /// @param hookData Additional data for hooks.
    /// @return claimed The amount of rewards claimed.
    function _claim(ClaimData memory data, bytes calldata hookData)
        internal
        notClosed(data.campaignId)
        validEpoch(data.campaignId, data.epoch)
        checkWhitelistOrBlacklist(data.campaignId, data.account, data.epoch)
        returns (uint256 claimed)
    {
        /// Update the epoch if needed.
        data.epoch = _updateEpoch(data.campaignId, data.epoch, hookData);

        /// Check if the account respect the conditions to claim.
        if (!_canClaim(data)) return 0;

        /// Get the amount to claim and the fee amount.
        (data.amountToClaim, data.feeAmount) = _calculateClaimAndFee(data);

        /// Check if the total claimed amount plus the claimed amount exceeds the total reward amount.
        if (
            totalClaimedByCampaignId[data.campaignId] + data.amountToClaim + data.feeAmount
                > campaignById[data.campaignId].totalRewardAmount
        ) revert CLAIM_AMOUNT_EXCEEDS_REWARD_AMOUNT();

        /// Update the total claimed amount for the account in this campaign and epoch.
        _updateClaimState(data);

        /// Transfer the tokens to the receiver.
        _transferTokens(data);

        emit Claim(data.campaignId, data.account, data.amountToClaim, data.feeAmount, data.epoch);

        return data.amountToClaim;
    }

    /// @notice Checks if a claim is valid.
    /// @param data The claim data.
    /// @return bool True if the claim is valid, false otherwise.
    function _canClaim(ClaimData memory data) internal view returns (bool) {
        // 1. Retrieve the campaign from storage.
        Campaign storage campaign = campaignById[data.campaignId];

        // 2. Check if the vote is valid using the ORACLE.
        bool canClaimFromOracle = IOracleLens(ORACLE).isVoteValid(data.account, campaign.gauge, data.epoch);

        // 3. Check if the claim deadline has not passed.
        bool withinClaimDeadline = campaign.endTimestamp + CLAIM_WINDOW_LENGTH > block.timestamp;

        // 4. Check if the account has not claimed before or if there's a new reward available.
        bool notClaimedOrNoReward = totalClaimedByAccount[data.campaignId][data.epoch][data.account] == 0
            || periodByCampaignId[data.campaignId][data.epoch].rewardPerVote == 0;

        // 5. Return true if all conditions are met.
        return canClaimFromOracle && withinClaimDeadline && notClaimedOrNoReward;
    }

    /// @notice Calculates the claim amount and fee.
    /// @param data The claim data.
    /// @return amountToClaim The amount of rewards to claim.
    /// @return feeAmount The fee amount.
    function _calculateClaimAndFee(ClaimData memory data)
        internal
        view
        returns (uint256 amountToClaim, uint256 feeAmount)
    {
        // 1. Retrieve the campaign from storage.
        Campaign storage campaign = campaignById[data.campaignId];

        // 2. Get the account's votes from the ORACLE.
        uint256 accountVote = IOracleLens(ORACLE).getAccountVotes(data.account, campaign.gauge, data.epoch);

        // 3. Calculate the amount to claim based on the account's votes and the reward per vote.
        amountToClaim = accountVote.mulDiv(periodByCampaignId[data.campaignId][data.epoch].rewardPerVote, 1e18);

        // 4. Determine the fee percentage (custom fee for the manager or default fee).
        uint256 feeBps = customFeeByManager[campaign.manager] > 0 ? customFeeByManager[campaign.manager] : fee;

        // 5. Calculate the fee amount.
        feeAmount = amountToClaim.mulDiv(feeBps, 1e18);

        // 6. Subtract the fee from the amount to claim.
        amountToClaim -= feeAmount;
    }

    /// @notice Updates the claim state.
    /// @param data The claim data.
    function _updateClaimState(ClaimData memory data) internal {
        // 1. Update the total claimed amount for the account in this campaign and epoch.
        totalClaimedByAccount[data.campaignId][data.epoch][data.account] = data.amountToClaim + data.feeAmount;

        // 2. Update the total claimed amount for the campaign.
        totalClaimedByCampaignId[data.campaignId] += data.amountToClaim + data.feeAmount;
    }

    /// @notice Transfers tokens for a claim.
    /// @param data The claim data.
    function _transferTokens(ClaimData memory data) internal {
        // 1. Get the reward token for the campaign.
        address rewardToken = campaignById[data.campaignId].rewardToken;

        // 2. Transfer the claimed amount to the receiver.
        SafeTransferLib.safeTransfer(rewardToken, data.receiver, data.amountToClaim);

        // 3. Transfer the fee to the fee collector.
        SafeTransferLib.safeTransfer(rewardToken, feeCollector, data.feeAmount);
    }

    /// @notice Updates the epoch for a campaign.
    /// @param campaignId The ID of the campaign.
    /// @param epoch The epoch to update.
    /// @param hookData Additional data for hooks.
    /// @return epoch_ The updated epoch.
    function updateEpoch(uint256 campaignId, uint256 epoch, bytes calldata hookData)
        external
        nonReentrant
        notClosed(campaignId)
        validEpoch(campaignId, epoch)
        returns (uint256 epoch_)
    {
        epoch_ = _updateEpoch(campaignId, epoch, hookData);
    }

    /// @notice Internal function to update the epoch.
    /// @param campaignId The ID of the campaign.
    /// @param epoch The epoch to update.
    /// @param hookData Additional data for hooks.
    /// @return The updated epoch.
    function _updateEpoch(uint256 campaignId, uint256 epoch, bytes calldata hookData) internal returns (uint256) {
        // 1. Get the period for the current epoch.
        Period storage period = _getPeriod(campaignId, epoch);
        if (period.updated) return epoch;

        // 2. Check for any pending upgrades.
        _checkForUpgrade(campaignId, epoch);

        // 3. Validate the previous state if not the first period.
        if (epoch >= campaignById[campaignId].startTimestamp + EPOCH_LENGTH) {
            _validatePreviousState(campaignId, epoch);
        }

        // 4. Calculate remaining periods and total reward.
        uint256 remainingPeriods = getRemainingPeriods(campaignId, epoch);
        uint256 totalRewardForRemainingPeriods = _calculateTotalReward(campaignId);

        // 5. Update the period data.
        period.rewardPerPeriod = remainingPeriods > 0
            ? totalRewardForRemainingPeriods.mulDiv(1, remainingPeriods)
            : totalRewardForRemainingPeriods;

        // 6. Update the reward per vote
        _updateRewardPerVote(campaignId, epoch, period, hookData);

        // 7. Update the total distributed amount
        campaignById[campaignId].totalDistributed += (period.rewardPerPeriod - period.leftover);

        // 8. Mark the period as updated
        period.updated = true;
        return epoch;
    }

    /// @notice Validates the previous state of a campaign.
    /// @param campaignId The ID of the campaign.
    /// @param epoch The current epoch.
    function _validatePreviousState(uint256 campaignId, uint256 epoch) internal view {
        Period storage previousPeriod = periodByCampaignId[campaignId][epoch - EPOCH_LENGTH];
        if (!previousPeriod.updated) {
            revert STATE_MISSING();
        }
    }

    /// @notice Gets the period for a campaign and epoch.
    /// @param campaignId The ID of the campaign.
    /// @param epoch The epoch.
    /// @return Period The period data.
    function _getPeriod(uint256 campaignId, uint256 epoch) internal view returns (Period storage) {
        return periodByCampaignId[campaignId][epoch];
    }

    /// @notice Calculates the total reward for remaining periods.
    /// @param campaignId The ID of the campaign.
    /// @return totalReward The total reward for remaining periods.
    function _calculateTotalReward(uint256 campaignId) internal view returns (uint256 totalReward) {
        totalReward = campaignById[campaignId].totalRewardAmount - campaignById[campaignId].totalDistributed;
        return totalReward;
    }

    /// @notice Updates the reward per vote for a campaign.
    /// @param campaignId The ID of the campaign.
    /// @param epoch The current epoch.
    /// @param period The period data.
    /// @param hookData Additional data for hooks.
    function _updateRewardPerVote(uint256 campaignId, uint256 epoch, Period storage period, bytes calldata hookData)
        internal
    {
        // 1. Get total adjusted votes
        uint256 totalVotes = _getAdjustedVote(campaignId, epoch);

        // 2. If no votes, rollover the leftover to the next epoch.
        if (totalVotes == 0) {
            period.leftover = period.rewardPerPeriod;
            return;
        }

        Campaign storage campaign = campaignById[campaignId];

        // 3. Calculate reward per vote
        uint256 rewardPerVote = period.rewardPerPeriod.mulDiv(1e18, totalVotes);

        // 4. Cap reward per vote at max reward per vote
        if (rewardPerVote > campaign.maxRewardPerVote) {
            rewardPerVote = campaign.maxRewardPerVote;

            // 5. Calculate leftover rewards
            uint256 leftOver = period.rewardPerPeriod - rewardPerVote.mulDiv(totalVotes, 1e18);

            // 6. Handle leftover rewards
            address hook = campaign.hook;
            if (hook != address(0)) {
                // Transfer leftover to hook contract
                SafeTransferLib.safeTransfer({token: campaign.rewardToken, to: hook, amount: leftOver});
                // Trigger the hook
                hook.call(
                    abi.encodeWithSelector(
                        IHook.doSomething.selector,
                        campaignId,
                        campaign.chainId,
                        campaign.rewardToken,
                        epoch,
                        leftOver,
                        hookData
                    )
                );

                // Consider the leftover as claimed.
                totalClaimedByCampaignId[campaignId] += leftOver;
            } else {
                // Store leftover in the period.
                period.leftover += leftOver;
            }
        }

        // 6. Save the calculated reward per vote.
        period.rewardPerVote = rewardPerVote;
    }

    /// @notice Calculates the adjusted total votes for a campaign.
    /// @param campaignId The ID of the campaign.
    /// @param epoch The current epoch.
    /// @return The adjusted total votes.
    function _getAdjustedVote(uint256 campaignId, uint256 epoch) internal view returns (uint256) {
        // 1. Get the addresses set for the campaign
        EnumerableSetLib.AddressSet storage addressesSet_ = addressesByCampaignId[campaignId];

        // 2. Get the total votes from the ORACLE
        uint256 totalVotes = IOracleLens(ORACLE).getTotalVotes(campaignById[campaignId].gauge, epoch);

        // 3. Calculate the sum of blacklisted votes.
        uint256 addressesVotes;
        for (uint256 i = 0; i < addressesSet_.length(); i++) {
            addressesVotes +=
                IOracleLens(ORACLE).getAccountVotes(addressesSet_.at(i), campaignById[campaignId].gauge, epoch);
        }

        if (whitelistOnly[campaignId]) {
            return addressesVotes;
        }

        // 4. Return the adjusted total votes.
        return totalVotes - addressesVotes;
    }

    /// @notice Creates a new incentive campaign.
    /// @param chainId The chain ID for the campaign.
    /// @param gauge The gauge address.
    /// @param manager The manager address.
    /// @param rewardToken The reward token address.
    /// @param numberOfPeriods The number of periods for the campaign.
    /// @param maxRewardPerVote The maximum reward per vote.
    /// @param totalRewardAmount The total reward amount.
    /// @param addresses The list of addresses blacklist or whitelist.
    /// @param hook The hook contract address.
    /// @param isWhitelist Whether the campaign uses a whitelist.
    /// @return campaignId The ID of the created campaign.
    function createCampaign(
        uint256 chainId,
        address gauge,
        address manager,
        address rewardToken,
        uint8 numberOfPeriods,
        uint256 maxRewardPerVote,
        uint256 totalRewardAmount,
        address[] calldata addresses,
        address hook,
        bool isWhitelist
    ) external nonReentrant returns (uint256 campaignId) {
        // 1. Input validation
        if (numberOfPeriods < MINIMUM_PERIODS) revert INVALID_INPUT();
        if (totalRewardAmount == 0 || maxRewardPerVote == 0) revert ZERO_INPUT();
        if (rewardToken == address(0) || gauge == address(0)) revert ZERO_ADDRESS();
        if (addresses.length > MAX_ADDRESSES_PER_CAMPAIGN) revert INVALID_INPUT();

        // 2. Check if reward token is a contract
        uint256 size;
        assembly {
            size := extcodesize(rewardToken)
        }
        if (size == 0) revert INVALID_TOKEN();

        // 3. Transfer reward token to this contract
        SafeTransferLib.safeTransferFrom({
            token: rewardToken,
            from: msg.sender,
            to: address(this),
            amount: totalRewardAmount
        });

        // 4. Generate campaign Id and get current epoch
        campaignId = campaignCount;

        // 5. Increment campaign count
        ++campaignCount;

        uint256 startTimestamp = currentEpoch() + EPOCH_LENGTH;

        // 6. Store campaign
        campaignById[campaignId] = Campaign({
            chainId: chainId,
            gauge: gauge,
            manager: manager,
            rewardToken: rewardToken,
            numberOfPeriods: numberOfPeriods,
            maxRewardPerVote: maxRewardPerVote,
            totalRewardAmount: totalRewardAmount,
            totalDistributed: 0,
            startTimestamp: startTimestamp,
            endTimestamp: startTimestamp + numberOfPeriods * EPOCH_LENGTH,
            hook: hook
        });

        /// 7. Set the reward per period for the first period.
        periodByCampaignId[campaignId][startTimestamp].rewardPerPeriod = totalRewardAmount.mulDiv(1, numberOfPeriods);

        /// 8. Add the addresses to the campaign.
        EnumerableSetLib.AddressSet storage addresses_ = addressesByCampaignId[campaignId];
        for (uint256 i = 0; i < addresses.length; i++) {
            if (addresses[i] == address(0)) continue;
            addresses_.add(addresses[i]);
        }

        // 9. Flag if the campaign is whitelist only
        whitelistOnly[campaignId] = isWhitelist;

        emit CampaignCreated(
            campaignId, gauge, manager, rewardToken, numberOfPeriods, maxRewardPerVote, totalRewardAmount
        );
    }

    /// @notice Manages the campaign duration, total reward amount, and max reward per vote.
    /// @param campaignId The ID of the campaign.
    /// @param numberOfPeriods Number of periods to add.
    /// @param totalRewardAmount Total reward amount to add.
    /// @param maxRewardPerVote Max reward per vote to set.
    function manageCampaign(
        uint256 campaignId,
        uint8 numberOfPeriods,
        uint256 totalRewardAmount,
        uint256 maxRewardPerVote
    ) external nonReentrant onlyManagerOrRemote(campaignId) notClosed(campaignId) {
        uint256 epoch = currentEpoch();
        // 1. Check if the campaign is ended.
        if (getRemainingPeriods(campaignId, epoch) <= 1) revert CAMPAIGN_ENDED();

        // 2. Get the campaign.
        Campaign storage campaign = campaignById[campaignId];

        if (campaign.startTimestamp <= epoch && !periodByCampaignId[campaignId][epoch].updated) {
            revert STATE_MISSING();
        }

        // 3. Calculate the next epoch.
        epoch += EPOCH_LENGTH;

        // 4. Check if there's a campaign upgrade in queue for this epoch.
        CampaignUpgrade memory campaignUpgrade = campaignUpgradeById[campaignId][epoch];

        // 5. Transfer additional reward tokens if needed.
        if (totalRewardAmount != 0) {
            SafeTransferLib.safeTransferFrom({
                token: campaign.rewardToken,
                from: msg.sender,
                to: address(this),
                amount: totalRewardAmount
            });
        }

        // 6. Update campaign upgrade
        if (campaignUpgrade.totalRewardAmount != 0) {
            campaignUpgrade = CampaignUpgrade({
                numberOfPeriods: campaignUpgrade.numberOfPeriods + numberOfPeriods,
                totalRewardAmount: campaignUpgrade.totalRewardAmount + totalRewardAmount,
                maxRewardPerVote: maxRewardPerVote > 0 ? maxRewardPerVote : campaignUpgrade.maxRewardPerVote,
                endTimestamp: campaignUpgrade.endTimestamp + (numberOfPeriods * EPOCH_LENGTH)
            });
        } else {
            campaignUpgrade = CampaignUpgrade({
                numberOfPeriods: campaign.numberOfPeriods + numberOfPeriods,
                totalRewardAmount: campaign.totalRewardAmount + totalRewardAmount,
                maxRewardPerVote: maxRewardPerVote > 0 ? maxRewardPerVote : campaign.maxRewardPerVote,
                endTimestamp: campaign.endTimestamp + (numberOfPeriods * EPOCH_LENGTH)
            });
        }

        // 7. Store the campaign upgrade in queue
        campaignUpgradeById[campaignId][epoch] = campaignUpgrade;

        emit CampaignUpgradeQueued(campaignId, epoch);
    }

    /// @notice Increases the total reward amount for a campaign
    /// @param campaignId The ID of the campaign
    /// @param totalRewardAmount Total reward amount to add
    function increaseTotalRewardAmount(uint256 campaignId, uint256 totalRewardAmount)
        external
        nonReentrant
        notClosed(campaignId)
    {
        uint256 epoch = currentEpoch();
        // 1. Check for zero input and check if the campaign is ended.
        if (totalRewardAmount == 0) revert ZERO_INPUT();
        if (getRemainingPeriods(campaignId, epoch) <= 1) revert CAMPAIGN_ENDED();

        // 2. Check if there's a campaign upgrade in queue for the previous epoch.
        CampaignUpgrade memory campaignUpgrade = campaignUpgradeById[campaignId][epoch];
        if (campaignUpgrade.totalRewardAmount != 0 && !periodByCampaignId[campaignId][epoch].updated) {
            revert STATE_MISSING();
        }

        // 3. Calculate the next epoch
        epoch += EPOCH_LENGTH;

        // 4. Get the campaign
        Campaign storage campaign = campaignById[campaignId];

        // 5. Check if there's a campaign upgrade in queue
        campaignUpgrade = campaignUpgradeById[campaignId][epoch];

        // 6. Transfer additional reward tokens
        SafeTransferLib.safeTransferFrom({
            token: campaign.rewardToken,
            from: msg.sender,
            to: address(this),
            amount: totalRewardAmount
        });

        // 7. Update campaign upgrade
        if (campaignUpgrade.totalRewardAmount != 0) {
            campaignUpgrade.totalRewardAmount += totalRewardAmount;
        } else {
            campaignUpgrade = CampaignUpgrade({
                numberOfPeriods: campaign.numberOfPeriods,
                totalRewardAmount: campaign.totalRewardAmount + totalRewardAmount,
                maxRewardPerVote: campaign.maxRewardPerVote,
                endTimestamp: campaign.endTimestamp
            });
        }

        // 8. Store the updated campaign upgrade
        campaignUpgradeById[campaignId][epoch] = campaignUpgrade;

        emit CampaignUpgradeQueued(campaignId, epoch);
    }

    /// @notice Closes a campaign
    /// @param campaignId The ID of the campaign to close
    function closeCampaign(uint256 campaignId) external notClosed(campaignId) nonReentrant {
        // 1. Get campaign data and calculate time windows
        Campaign storage campaign = campaignById[campaignId];
        uint256 currentTime = block.timestamp;
        uint256 claimWindow = campaign.endTimestamp + CLAIM_WINDOW_LENGTH;
        uint256 closeWindow = claimWindow + CLOSE_WINDOW_LENGTH;
        address receiver = campaign.manager;

        // 2. Handle different closing scenarios
        if (currentTime < campaign.startTimestamp) {
            // 2a. Campaign hasn't started yet
            _isManagerOrRemote(campaignId);
            _checkForUpgrade(campaignId, campaign.startTimestamp);
        } else if (currentTime < claimWindow) {
            // 2b. Campaign is ongoing or within claim window
            revert CAMPAIGN_NOT_ENDED();
        } else if (currentTime < closeWindow) {
            // 2c. Within close window, only manager can close
            _isManagerOrRemote(campaignId);
            _validatePreviousState(campaignId, campaign.endTimestamp);
        } else {
            // 2d. After close window, anyone can close and funds go to fee collector
            _validatePreviousState(campaignId, campaign.endTimestamp);
            receiver = feeCollector;
        }

        // 3. Close the campaign
        _closeCampaign(campaignId, campaign.totalRewardAmount, campaign.rewardToken, receiver);
    }

    /// @notice Internal function to close a campaign
    /// @param campaignId The ID of the campaign
    /// @param totalRewardAmount Total reward amount
    /// @param rewardToken The reward token address
    /// @param receiver The address to receive leftover rewards
    function _closeCampaign(uint256 campaignId, uint256 totalRewardAmount, address rewardToken, address receiver)
        internal
    {
        // 1. Calculate leftover rewards
        uint256 leftOver = totalRewardAmount - totalClaimedByCampaignId[campaignId];

        // 2. Transfer leftover rewards to the receiver
        SafeTransferLib.safeTransfer({token: rewardToken, to: receiver, amount: leftOver});

        // 3. Update the total claimed amount
        totalClaimedByCampaignId[campaignId] = totalRewardAmount;

        // 4. Set the campaign as closed
        isClosedCampaign[campaignId] = true;

        emit CampaignClosed(campaignId);
    }

    /// @notice Checks for and applies any pending upgrades to a campaign
    /// @param campaignId The ID of the campaign
    /// @param epoch The current epoch
    function _checkForUpgrade(uint256 campaignId, uint256 epoch) internal {
        // 1. Get the campaign upgrade
        CampaignUpgrade memory campaignUpgrade = campaignUpgradeById[campaignId][epoch];

        // 2. Check if there is an upgrade in queue
        if (campaignUpgrade.totalRewardAmount != 0) {
            // 3. Get the campaign
            Campaign storage campaign = campaignById[campaignId];

            // 7. Save new campaign values
            campaign.endTimestamp = campaignUpgrade.endTimestamp;
            campaign.numberOfPeriods = campaignUpgrade.numberOfPeriods;
            campaign.maxRewardPerVote = campaignUpgrade.maxRewardPerVote;
            campaign.totalRewardAmount = campaignUpgrade.totalRewardAmount;

            emit CampaignUpgraded(campaignId, epoch);
        }
    }

    ////////////////////////////////////////////////////////////////
    /// --- VIEW FUNCTIONS
    ///////////////////////////////////////////////////////////////

    /// @notice Returns the number of weeks before the campaign ends
    /// @param campaignId The ID of the campaign
    /// @param epoch The current epoch
    /// @return periodsLeft The number of periods left
    function getRemainingPeriods(uint256 campaignId, uint256 epoch) public view returns (uint256 periodsLeft) {
        Campaign storage campaign = campaignById[campaignId];
        periodsLeft = campaign.endTimestamp > epoch ? (campaign.endTimestamp - epoch) / EPOCH_LENGTH : 0;
    }

    /// @notice Gets a campaign by its ID
    /// @param campaignId The ID of the campaign
    /// @return Campaign The campaign data
    function getCampaign(uint256 campaignId) public view returns (Campaign memory) {
        return campaignById[campaignId];
    }

    /// @notice Gets a campaign upgrade by its ID and epoch
    /// @param campaignId The ID of the campaign
    /// @param epoch The epoch of the upgrade
    /// @return CampaignUpgrade The campaign upgrade data
    function getCampaignUpgrade(uint256 campaignId, uint256 epoch) public view returns (CampaignUpgrade memory) {
        return campaignUpgradeById[campaignId][epoch];
    }

    /// @notice Gets the blacklist for a campaign
    /// @param campaignId The ID of the campaign
    /// @return address[] The array of blacklisted addresses
    function getAddressesByCampaign(uint256 campaignId) public view returns (address[] memory) {
        return addressesByCampaignId[campaignId].values();
    }

    /// @notice Gets a period for a campaign
    /// @param campaignId The ID of the campaign
    /// @param epoch The epoch of the period
    /// @return Period The period data
    function getPeriodPerCampaign(uint256 campaignId, uint256 epoch) public view returns (Period memory) {
        return periodByCampaignId[campaignId][epoch];
    }

    /// @notice Gets the current epoch
    /// @return uint256 The current epoch
    function currentEpoch() public view returns (uint256) {
        return block.timestamp / EPOCH_LENGTH * EPOCH_LENGTH;
    }

    ////////////////////////////////////////////////////////////////
    /// --- SETTERS
    ///////////////////////////////////////////////////////////////

    /// @notice Sets if an account is protected
    /// @param _account The account address
    /// @param _isProtected The new is protected value
    function setIsProtected(address _account, bool _isProtected) external onlyGovernance {
        isProtected[_account] = _isProtected;
    }

    /// @notice Sets the remote address
    /// @param _remote The new remote address
    function setRemote(address _remote) external onlyGovernance {
        // 1. Check for zero address
        if (_remote == address(0)) revert ZERO_ADDRESS();

        // 2. Set the new remote address
        remote = _remote;
    }

    /// @notice Sets the fee
    /// @param _fee The new fee (in basis points)
    function setFee(uint256 _fee) external onlyGovernance {
        if (_fee > 10e16) revert INVALID_INPUT();
        fee = _fee;
    }

    /// @notice Sets a custom fee for a manager
    /// @param _account The manager address
    /// @param _fee The new fee (in basis points)
    function setCustomFee(address _account, uint256 _fee) external onlyGovernance {
        if (_fee > 10e16) revert INVALID_INPUT();
        customFeeByManager[_account] = _fee;
    }

    /// @notice Sets a recipient for the sender
    /// @param _recipient The new recipient address
    function setRecipient(address _recipient) external {
        recipients[msg.sender] = _recipient;
    }

    /// @notice Sets a recipient for an account
    /// @param _account The account address
    /// @param _recipient The new recipient address
    function setRecipient(address _account, address _recipient) external onlyGovernance {
        recipients[_account] = _recipient;
    }

    /// @notice Sets the fee collector address
    /// @param _feeCollector The new fee collector address
    function setFeeCollector(address _feeCollector) external onlyGovernance {
        if (_feeCollector == address(0)) revert ZERO_ADDRESS();
        feeCollector = _feeCollector;
    }

    /// @notice Sets the future governance address
    /// @param _futureGovernance The new future governance address
    function transferGovernance(address _futureGovernance) external onlyGovernance {
        if (_futureGovernance == address(0)) revert ZERO_ADDRESS();
        futureGovernance = _futureGovernance;
    }

    /// @notice Accepts the governance role via the future governance address
    function acceptGovernance() external {
        if (msg.sender != futureGovernance) revert AUTH_GOVERNANCE_ONLY();
        governance = futureGovernance;
        futureGovernance = address(0);
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_feeCollector","type":"address"},{"internalType":"uint256","name":"_epochLength","type":"uint256"},{"internalType":"uint8","name":"_minimumPeriods","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AUTH_BLACKLISTED","type":"error"},{"inputs":[],"name":"AUTH_GOVERNANCE_ONLY","type":"error"},{"inputs":[],"name":"AUTH_MANAGER_ONLY","type":"error"},{"inputs":[],"name":"AUTH_WHITELIST_ONLY","type":"error"},{"inputs":[],"name":"CAMPAIGN_ENDED","type":"error"},{"inputs":[],"name":"CAMPAIGN_NOT_ENDED","type":"error"},{"inputs":[],"name":"CLAIM_AMOUNT_EXCEEDS_REWARD_AMOUNT","type":"error"},{"inputs":[],"name":"EPOCH_NOT_VALID","type":"error"},{"inputs":[],"name":"INVALID_INPUT","type":"error"},{"inputs":[],"name":"INVALID_TOKEN","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"PROTECTED_ACCOUNT","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"STATE_MISSING","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"inputs":[],"name":"ZERO_INPUT","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"CampaignClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"address","name":"gauge","type":"address"},{"indexed":false,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalRewardAmount","type":"uint256"}],"name":"CampaignCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"CampaignUpgradeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"CampaignUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"Claim","type":"event"},{"inputs":[],"name":"CLAIM_WINDOW_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CLOSE_WINDOW_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EPOCH_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ADDRESSES_PER_CAMPAIGN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_PERIODS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addressesByCampaignId","outputs":[{"internalType":"uint256","name":"_spacer","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaignById","outputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"gauge","type":"address"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"uint256","name":"totalDistributed","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"address","name":"hook","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"campaignCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaignUpgradeById","outputs":[{"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"},{"internalType":"address","name":"receiver","type":"address"}],"name":"claim","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"name":"claim","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"closeCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"gauge","type":"address"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"address","name":"hook","type":"address"},{"internalType":"bool","name":"isWhitelist","type":"bool"}],"name":"createCampaign","outputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"customFeeByManager","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"futureGovernance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"getAddressesByCampaign","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"getCampaign","outputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"gauge","type":"address"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"address","name":"rewardToken","type":"address"},{"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"uint256","name":"totalDistributed","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"address","name":"hook","type":"address"}],"internalType":"struct Campaign","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getCampaignUpgrade","outputs":[{"components":[{"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"internalType":"struct CampaignUpgrade","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getPeriodPerCampaign","outputs":[{"components":[{"internalType":"uint256","name":"rewardPerPeriod","type":"uint256"},{"internalType":"uint256","name":"rewardPerVote","type":"uint256"},{"internalType":"uint256","name":"leftover","type":"uint256"},{"internalType":"bool","name":"updated","type":"bool"}],"internalType":"struct Period","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getRemainingPeriods","outputs":[{"internalType":"uint256","name":"periodsLeft","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"}],"name":"increaseTotalRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isClosedCampaign","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isProtected","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint8","name":"numberOfPeriods","type":"uint8"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"uint256","name":"maxRewardPerVote","type":"uint256"}],"name":"manageCampaign","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"periodByCampaignId","outputs":[{"internalType":"uint256","name":"rewardPerPeriod","type":"uint256"},{"internalType":"uint256","name":"rewardPerVote","type":"uint256"},{"internalType":"uint256","name":"leftover","type":"uint256"},{"internalType":"bool","name":"updated","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"recipients","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"remote","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setCustomFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_isProtected","type":"bool"}],"name":"setIsProtected","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"setRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"setRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_remote","type":"address"}],"name":"setRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"totalClaimedByAccount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalClaimedByCampaignId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_futureGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"bytes","name":"hookData","type":"bytes"}],"name":"updateEpoch","outputs":[{"internalType":"uint256","name":"epoch_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"whitelistOnly","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

0x60e06040523480156200001157600080fd5b50604051620037fe380380620037fe8339810160408190526200003491620000a2565b600080546001600160a01b03199081166001600160a01b03978816179091556003805490911693861693909317909255668e1bc9bf0400006004559190921660c05260a05260ff1660805262000112565b80516001600160a01b03811681146200009d57600080fd5b919050565b600080600080600060a08688031215620000bb57600080fd5b620000c68662000085565b9450620000d66020870162000085565b9350620000e66040870162000085565b925060608601519150608086015160ff811681146200010457600080fd5b809150509295509295909350565b60805160a05160c051613645620001b96000396000818161035101528181612750015281816128af01528181612d240152612daf01526000818161079901528181610d8001528181610e7401528181610f1701528181611005015281816111eb0152818161134601528181611650015281816116e601528181611c1d01528181611e340152818161223701526123f00152600081816105b1015261153c01526136456000f3fe608060405234801561001057600080fd5b506004361061027f5760003560e01c80638070c5031161015c578063b0e1c1e1116100ce578063d598215b11610087578063d598215b1461083d578063ddca3f4314610850578063df4c3d1014610859578063eb8203121461087c578063f1efe24c146108a5578063fffa86fc146108b857600080fd5b8063b0e1c1e1146107bb578063b956358c146107ce578063c415b95c146107e1578063ce35de95146107f4578063d38bfff414610817578063d49466a81461082a57600080fd5b8063990161421161012057806399016142146106e357806399e9d29e146106f65780639dd535971461075b578063a42dce801461076e578063a4bb094614610781578063ac4746ab1461079457600080fd5b80638070c503146105865780638bc8407a146105995780638e3c282b146105ac5780638e57daa7146105e557806398bf6de81461060557600080fd5b806352aed578116101f557806366629f12116101b957806366629f12146104fe57806369fe0e2d1461052f5780636dbb5011146105425780636fb08df2146105555780637274e30d14610575578063766718081461057e57600080fd5b806352aed578146104305780635598f8cc1461047857806355b88ff6146104985780635aa6e675146104cb5780635dda2d63146104de57600080fd5b80631ec72172116102475780631ec7217214610325578063238efcbc1461033a5780632a0621d71461034257806338013f021461034c5780633bbed4a01461038b5780633ce9772e146103c857600080fd5b806303f17e561461028457806309066d7c146102b75780630f62accf146102ca57806317f3a722146102d25780631ac5c6ee1461031b575b600080fd5b6102a4610292366004612f79565b60086020526000908152604090205481565b6040519081526020015b60405180910390f35b6102a46102c5366004612fe4565b6108cb565b6102a4603281565b6102e56102e036600461304c565b610959565b6040516102ae9190815160ff16815260208083015190820152604080830151908201526060918201519181019190915260800190565b6102a462dd7c0081565b610338610333366004613087565b6109db565b005b610338610a31565b6102a46224ea0081565b6103737f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102ae565b610338610399366004612f79565b33600090815260076020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b61040c6103d636600461304c565b600c602090815260009283526040808420909152908252902080546001820154600283015460039093015460ff90921692909184565b6040805160ff909516855260208501939093529183015260608201526080016102ae565b61044361043e36600461304c565b610a83565b6040516102ae919081518152602080830151908201526040808301519082015260609182015115159181019190915260800190565b61048b6104863660046130be565b610b01565b6040516102ae91906130d7565b6104bb6104a63660046130be565b600a6020526000908152604090205460ff1681565b60405190151581526020016102ae565b600054610373906001600160a01b031681565b6102a46104ec3660046130be565b600d6020526000908152604090205481565b6102a461050c366004613198565b600e60209081526000938452604080852082529284528284209052825290205481565b61033861053d3660046130be565b610c28565b6103386105503660046131de565b610c81565b6105686105633660046130be565b610fe7565b6040516102ae9190613219565b6102a460055481565b6102a4611001565b600154610373906001600160a01b031681565b6103386105a7366004613266565b61103d565b6105d37f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102ae565b6102a46105f33660046130be565b60106020526000908152604090205481565b6106826106133660046130be565b6009602081905260009182526040909120805460018201546002830154600384015460048501546005860154600687015460078801546008890154989099015496986001600160a01b03968716989587169787861697600160a01b90960460ff1696949593949293919291168b565b604080519b8c526001600160a01b039a8b1660208d0152988a16988b019890985295881660608a015260ff909416608089015260a088019290925260c087015260e086015261010085015261012084015216610140820152610160016102ae565b6102a46106f1366004613299565b611096565b61073961070436600461304c565b600b60209081526000928352604080842090915290825290208054600182015460028301546003909301549192909160ff1684565b60408051948552602085019390935291830152151560608201526080016102ae565b6102a461076936600461304c565b6111c9565b61033861077c366004612f79565b61122c565b6102a461078f366004613301565b6112a0565b6102a47f000000000000000000000000000000000000000000000000000000000000000081565b6103386107c93660046130be565b6113b0565b6102a46107dc366004613354565b61150d565b600354610373906001600160a01b031681565b6104bb610802366004612f79565b60066020526000908152604090205460ff1681565b610338610825366004612f79565b61197a565b61033861083836600461344d565b6119ee565b600254610373906001600160a01b031681565b6102a460045481565b6104bb6108673660046130be565b600f6020526000908152604090205460ff1681565b61037361088a366004612f79565b6007602052600090815260409020546001600160a01b031681565b6103386108b3366004612f79565b611a5e565b6103386108c636600461304c565b611ad2565b60003068929eee149b4bd2126854036108ec5763ab143c066000526004601cfd5b3068929eee149b4bd21268556109436040518060c00160405280888152602001336001600160a01b03168152602001846001600160a01b031681526020018781526020016000815260200160008152508585611db3565b3868929eee149b4bd21268559695505050505050565b6109876040518060800160405280600060ff1681526020016000815260200160008152602001600081525090565b506000828152600c602090815260408083208484528252918290208251608081018452815460ff16815260018201549281019290925260028101549282019290925260039091015460608201525b92915050565b6000546001600160a01b03163314610a0657604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b6001546001600160a01b03163314610a5c57604051630c39d07960e01b815260040160405180910390fd5b60018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b610ab060405180608001604052806000815260200160008152602001600081526020016000151581525090565b506000918252600b60209081526040808420928452918152918190208151608081018352815481526001820154938101939093526002810154918301919091526003015460ff161515606082015290565b610b856040518061016001604052806000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600060ff168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b506000908152600960208181526040928390208351610160810185528154815260018201546001600160a01b0390811693820193909352600282015483169481019490945260038101548083166060860152600160a01b900460ff166080850152600481015460a0850152600581015460c0850152600681015460e085015260078101546101008501526008810154610120850152909101541661014082015290565b6000546001600160a01b03163314610c5357604051630c39d07960e01b815260040160405180910390fd5b67016345785d8a0000811115610c7c5760405163b68600c760e01b815260040160405180910390fd5b600455565b3068929eee149b4bd212685403610ca05763ab143c066000526004601cfd5b3068929eee149b4bd212685583610cb681612067565b6000858152600a6020526040902054859060ff1615610ce857604051630e1bf69160e01b815260040160405180910390fd5b6000610cf2611001565b90506001610d0088836111c9565b11610d1e57604051630e1bf69160e01b815260040160405180910390fd5b600087815260096020526040902060078101548210801590610d5d57506000888152600b6020908152604080832085845290915290206003015460ff16155b15610d7b5760405163c9936a5360e01b815260040160405180910390fd5b610da57f00000000000000000000000000000000000000000000000000000000000000008361348d565b6000898152600c602090815260408083208484528252918290208251608081018452815460ff16815260018201549281019290925260028101549282019290925260039091015460608201529092508615610e14576003820154610e14906001600160a01b031633308a6120bd565b602081015115610eb4576040518060800160405280898360000151610e3991906134a0565b60ff168152602001888360200151610e51919061348d565b815260200160008811610e68578260400151610e6a565b875b8152602001610e9c7f000000000000000000000000000000000000000000000000000000000000000060ff8c166134b9565b8360600151610eab919061348d565b90529050610f53565b6040518060800160405280898460030160149054906101000a900460ff16610edc91906134a0565b60ff168152602001888460050154610ef4919061348d565b815260200160008811610f0b578360040154610f0d565b875b8152602001610f3f7f000000000000000000000000000000000000000000000000000000000000000060ff8c166134b9565b8460080154610f4e919061348d565b905290505b6000898152600c602090815260408083208684528252918290208351815460ff191660ff909116178155838201516001820155838301516002820155606084015160039091015581518b81529081018590527fa8bf14cbd1773eaebffd457f5e6a2badb14741d5e87b85eb41e4adb86080ac0c910160405180910390a150505050503868929eee149b4bd212685550505050565b60008181526010602052604090206060906109d590612111565b60007f000000000000000000000000000000000000000000000000000000000000000061102e81426134e6565b61103891906134b9565b905090565b6000546001600160a01b0316331461106857604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b03918216600090815260076020526040902080546001600160a01b03191691909216179055565b60003068929eee149b4bd2126854036110b75763ab143c066000526004601cfd5b3068929eee149b4bd21268556001600160a01b03851660009081526006602052604090205460ff16801561110357506001600160a01b0385811660009081526007602052604090205416155b1561112157604051631128f5c960e01b815260040160405180910390fd5b6001600160a01b0385811660009081526007602052604081205490911615611163576001600160a01b0380871660009081526007602052604090205416611165565b855b90506111b26040518060c00160405280898152602001886001600160a01b03168152602001836001600160a01b031681526020018781526020016000815260200160008152508585611db3565b3868929eee149b4bd2126855979650505050505050565b6000828152600960205260408120600881015483106111e9576000611224565b7f000000000000000000000000000000000000000000000000000000000000000083826008015461121a91906134fa565b61122491906134e6565b949350505050565b6000546001600160a01b0316331461125757604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b03811661127e5760405163538ba4f960e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60003068929eee149b4bd2126854036112c15763ab143c066000526004601cfd5b3068929eee149b4bd21268556000858152600a6020526040902054859060ff16156112ff57604051630e1bf69160e01b815260040160405180910390fd5b85854281118061131f575060008281526009602052604090206007015481105b8061133b57506000828152600960205260409020600801548110155b8061136e575061136b7f00000000000000000000000000000000000000000000000000000000000000008261350d565b15155b1561138c576040516327a9565960e01b815260040160405180910390fd5b611398888888886121e6565b3868929eee149b4bd212685598975050505050505050565b6000818152600a6020526040902054819060ff16156113e257604051630e1bf69160e01b815260040160405180910390fd5b3068929eee149b4bd2126854036114015763ab143c066000526004601cfd5b3068929eee149b4bd212685560008281526009602052604081206008810154909142916114329062dd7c009061348d565b905060006114436224ea008361348d565b600285015460078601549192506001600160a01b03169084101561147d5761146a87612067565b611478878660070154612300565b6114d9565b8284101561149e5760405163966c987560e01b815260040160405180910390fd5b818410156114bd576114af87612067565b6114788786600801546123dc565b6114cb8786600801546123dc565b506003546001600160a01b03165b600585015460038601546114f89189916001600160a01b03168461244d565b50505050503868929eee149b4bd21268555050565b60003068929eee149b4bd21268540361152e5763ab143c066000526004601cfd5b3068929eee149b4bd21268557f000000000000000000000000000000000000000000000000000000000000000060ff168860ff1610156115815760405163b68600c760e01b815260040160405180910390fd5b85158061158c575086155b156115aa576040516360a6332360e01b815260040160405180910390fd5b6001600160a01b03891615806115c757506001600160a01b038b16155b156115e55760405163538ba4f960e01b815260040160405180910390fd5b60328411156116075760405163b68600c760e01b815260040160405180910390fd5b883b600081900361162b5760405163684cae7960e11b815260040160405180910390fd5b6116378a33308a6120bd565b600580549250600061164884613521565b9091555060007f0000000000000000000000000000000000000000000000000000000000000000611677611001565b611681919061348d565b90506040518061016001604052808f81526020018e6001600160a01b031681526020018d6001600160a01b031681526020018c6001600160a01b031681526020018b60ff1681526020018a8152602001898152602001600081526020018281526020017f00000000000000000000000000000000000000000000000000000000000000008c60ff1661171391906134b9565b61171d908461348d565b81526001600160a01b03808816602092830152600086815260098084526040918290208551815593850151600180860180549286166001600160a01b0319938416179055928601516002860180549186169183169190911790556060860151600386018054608089015160ff908116600160a01b026001600160a81b03199092169388169390931717905560a0870151600487015560c0870151600587015560e087015160068701556101008701516007870155610120870151600887015561014090960151949091018054949093169316929092179055611803918a91908d166124d1565b6000848152600b6020908152604080832085845282528083209390935585825260109052908120905b878110156118b05760008989838181106118485761184861353a565b905060200201602081019061185d9190612f79565b6001600160a01b03161461189e5761189c8989838181106118805761188061353a565b90506020020160208101906118959190612f79565b83906124f7565b505b806118a881613521565b91505061182c565b5084600f600086815260200190815260200160002060006101000a81548160ff0219169083151502179055507f0e291713fc4cb1bcf9276bc9ae54317736576d5353a44151e2e31c191b1ee62a848f8f8f8f8f8f60405161195497969594939291909687526001600160a01b039586166020880152938516604087015291909316606085015260ff92909216608084015260a083019190915260c082015260e00190565b60405180910390a15050503868929eee149b4bd21268559b9a5050505050505050505050565b6000546001600160a01b031633146119a557604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b0381166119cc5760405163538ba4f960e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314611a1957604051630c39d07960e01b815260040160405180910390fd5b67016345785d8a0000811115611a425760405163b68600c760e01b815260040160405180910390fd5b6001600160a01b03909116600090815260086020526040902055565b6000546001600160a01b03163314611a8957604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b038116611ab05760405163538ba4f960e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b3068929eee149b4bd212685403611af15763ab143c066000526004601cfd5b3068929eee149b4bd21268556000828152600a6020526040902054829060ff1615611b2f57604051630e1bf69160e01b815260040160405180910390fd5b6000611b39611001565b905082600003611b5c576040516360a6332360e01b815260040160405180910390fd5b6001611b6885836111c9565b11611b8657604051630e1bf69160e01b815260040160405180910390fd5b6000848152600c602090815260408083208484528252918290208251608081018452815460ff168152600182015492810183905260028201549381019390935260030154606083015215801590611bfa57506000858152600b6020908152604080832085845290915290206003015460ff16155b15611c185760405163c9936a5360e01b815260040160405180910390fd5b611c427f00000000000000000000000000000000000000000000000000000000000000008361348d565b6000868152600960209081526040808320600c83528184208585528352928190208151608081018352815460ff1681526001820154938101939093526002810154918301919091526003908101546060830152820154929450925090611cb3906001600160a01b03163330886120bd565b602082015115611cd7578482602001818151611ccf919061348d565b905250611d22565b60408051608081019091526003820154600160a01b900460ff16815260058201546020820190611d0890889061348d565b815260200182600401548152602001826008015481525091505b6000868152600c602090815260408083208684528252918290208451815460ff191660ff909116178155848201516001820155848301516002820155606085015160039091015581518881529081018590527fa8bf14cbd1773eaebffd457f5e6a2badb14741d5e87b85eb41e4adb86080ac0c910160405180910390a1505050503868929eee149b4bd21268555050565b82516000818152600a602052604081205490919060ff1615611de857604051630e1bf69160e01b815260040160405180910390fd5b8451606086015142811180611e0d575060008281526009602052604090206007015481105b80611e2957506000828152600960205260409020600801548110155b80611e5c5750611e597f00000000000000000000000000000000000000000000000000000000000000008261350d565b15155b15611e7a576040516327a9565960e01b815260040160405180910390fd5b865160208089015160608a0151600084815260109093526040832091929091611ea3908461264c565b6000858152600f602052604090205490915060ff168015611ec2575080155b15611ee0576040516307957bbf60e11b815260040160405180910390fd5b6000848152600f602052604090205460ff16158015611efc5750805b15611f1a5760405163e132c7cd60e01b815260040160405180910390fd5b611f2e8b600001518c606001518c8c6121e6565b60608c0152611f3c8b6126ff565b611f495760009750612059565b611f528b61285b565b8c6080018d60a00182815250828152505050600960008c600001518152602001908152602001600020600501548b60a001518c60800151600d60008f60000151815260200190815260200160002054611fab919061348d565b611fb5919061348d565b1115611fd45760405163506d8cdf60e11b815260040160405180910390fd5b611fdd8b6129ca565b611fe68b612a4e565b8a602001516001600160a01b03168b600001517f318e0a24a7fc05b12e358902d9d58475434a01768f87a4319fb35dc5b533e9868d608001518e60a001518f60600151604051612049939291909283526020830191909152604082015260600190565b60405180910390a38a6080015197505b505050505050509392505050565b6000818152600960205260409020600201546001600160a01b0316331480159061209c57506002546001600160a01b03163314155b156120ba5760405163fabbbc6760e01b815260040160405180910390fd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c52602060006064601c6000895af13d15600160005114171661210357637939f4246000526004601cfd5b600060605260405250505050565b63978aab926004526000818152602481206060915068fbb67fda52d4bfb8bf81548060a01b60a01c6040519450846020018260601c92508383141583028152816121a057821561219b57600191508185015460601c9250821561219b578284141590920260208301525060028381015460601c91821561219b576003915083831415830260408201525b6121d0565b600191821c915b828110156121ce578581015460601c858114158102600583901b84015293506001016121a7565b505b8186528160051b81016040525050505050919050565b6000848152600b602090815260408083208684529091528120600381015460ff16156122155784915050611224565b61221f8686612300565b60008681526009602052604090206007015461225c907f00000000000000000000000000000000000000000000000000000000000000009061348d565b851061226c5761226c86866123dc565b600061227887876111c9565b9050600061228588612aa7565b90506000821161229557806122a1565b6122a1816001846124d1565b83556122b08888858989612aca565b600283015483546122c191906134fa565b600089815260096020526040812060060180549091906122e290849061348d565b90915550505050600301805460ff1916600117905550919392505050565b6000828152600c602090815260408083208484528252918290208251608081018452815460ff1681526001820154928101839052600282015493810193909352600301546060830152156123d75760008381526009602090815260409182902060608401516008820155835160038201805460ff909216600160a01b0260ff60a01b199092169190911790558383015160048201558382015160058201558251868152918201859052917fa416776236c15a5c5398bdb783dfe811a1723512b5fb8914aeb21873defa1872910160405180910390a1505b505050565b6000828152600b60205260408120816124157f0000000000000000000000000000000000000000000000000000000000000000856134fa565b81526020810191909152604001600020600381015490915060ff166123d75760405163c9936a5360e01b815260040160405180910390fd5b6000848152600d602052604081205461246690856134fa565b9050612473838383612c9a565b6000858152600d60209081526040808320879055600a825291829020805460ff1916600117905590518681527f5e6eb33a418de5dbbc17f989f7ae362cdfbb1748c5d603137c767027a354edbc910160405180910390a15050505050565b828202831584820484141782026124f05763ad251c276000526004601cfd5b0492915050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be1983016125345763f5a267f16000526004601cfd5b826125465768fbb67fda52d4bfb8bf92505b80546bffffffffffffffffffffffff8116826020528061260e578160601c80612579578560601b84556001945050612643565b8581036125865750612643565b600184015460601c806125a7578660601b6001860155600195505050612643565b8681036125b5575050612643565b600285015460601c806125d7578760601b600287015560019650505050612643565b8781036125e657505050612643565b6000928352604080842060019055918352818320600290558252902060039055506007908117905b8460005260406000208054612641578160011c91508560601b828501558160010181558260020184556001945050612643565b505b50505092915050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be1983016126895763f5a267f16000526004601cfd5b8261269b5768fbb67fda52d4bfb8bf92505b80546bffffffffffffffffffffffff81166126e45760019250838160601c03156126f757600182015460601c84146126f757600282015460601c84146126f757600092506126f7565b8160205283600052604060002054151592505b505092915050565b8051600090815260096020908152604080832091840151600183015460608601519251635817dca560e11b81526001600160a01b0392831660048201529082166024820152604481019290925283917f00000000000000000000000000000000000000000000000000000000000000009091169063b02fb94a90606401602060405180830381865afa158015612799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bd9190613550565b905060004262dd7c0084600801546127d5919061348d565b86516000908152600e6020908152604080832060608b015184528252808320828b01516001600160a01b0316845290915281205492909111925090158061283c575085516000908152600b6020908152604080832060608a01518452909152902060010154155b90508280156128485750815b80156128515750805b9695505050505050565b8051600090815260096020908152604080832091840151600183015460608601519251630520fe4160e31b81526001600160a01b0392831660048201529082166024820152604481019290925283929183917f00000000000000000000000000000000000000000000000000000000000000001690632907f20890606401602060405180830381865afa1580156128f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291a919061356d565b85516000908152600b6020908152604080832060608a01518452909152902060010154909150612954908290670de0b6b3a76400006124d1565b60028301546001600160a01b0316600090815260086020526040812054919550906129815760045461299f565b60028301546001600160a01b03166000908152600860205260409020545b90506129b48582670de0b6b3a76400006124d1565b93506129c084866134fa565b9450505050915091565b8060a0015181608001516129de919061348d565b81516000908152600e60209081526040808320606086015184528252808320828601516001600160a01b0316845290915290205560a08101516080820151612a26919061348d565b81516000908152600d602052604081208054909190612a4690849061348d565b909155505050565b805160009081526009602052604090819020600301549082015160808301516001600160a01b0390921691612a84918391612c9a565b60035460a0830151612aa39183916001600160a01b0390911690612c9a565b5050565b600081815260096020526040812060068101546005909101546109d591906134fa565b6000612ad68686612ce0565b905080600003612aed575082546002840155612c93565b60008681526009602052604081208554909190612b1390670de0b6b3a7640000856124d1565b90508160040154811115612c8b575060048101546000612b3c8285670de0b6b3a76400006124d1565b8754612b4891906134fa565b60098401549091506001600160a01b03168015612c6e576003840154612b78906001600160a01b03168284612c9a565b806001600160a01b0316631406610660e01b8b86600001548760030160009054906101000a90046001600160a01b03168d878d8d604051602401612bc29796959493929190613586565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c0091906135e0565b6000604051808303816000865af19150503d8060008114612c3d576040519150601f19603f3d011682016040523d82523d6000602084013e612c42565b606091505b50505060008a8152600d602052604081208054849290612c6390849061348d565b90915550612c889050565b81886002016000828254612c82919061348d565b90915550505b50505b600186015550505b5050505050565b816014528060345263a9059cbb60601b60005260206000604460106000875af13d156001600051141716612cd6576390b8ec186000526004601cfd5b6000603452505050565b6000828152601060209081526040808320600990925280832060010154905163085a4a3d60e31b81526001600160a01b0391821660048201526024810185905283917f000000000000000000000000000000000000000000000000000000000000000016906342d251e890604401602060405180830381865afa158015612d6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d8f919061356d565b90506000805b612d9e84612eb1565b811015612e85576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016632907f208612dde8684612f03565b60008a8152600960205260409081902060010154905160e084901b6001600160e01b03191681526001600160a01b0392831660048201529116602482015260448101899052606401602060405180830381865afa158015612e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e67919061356d565b612e71908361348d565b915080612e7d81613521565b915050612d95565b506000868152600f602052604090205460ff1615612ea75792506109d5915050565b61285181836134fa565b63978aab9260045260008181526024812080548060a01b60a01c8060011c9350808260601c1517612efb57600193508383015415612efb57600293508383015415612efb57600393505b505050919050565b63978aab926004526000828152602481208281015460601c915068fbb67fda52d4bfb8bf82141582029150612f3784612eb1565b8310612f5657604051634e23d03560e01b815260040160405180910390fd5b5092915050565b80356001600160a01b0381168114612f7457600080fd5b919050565b600060208284031215612f8b57600080fd5b612f9482612f5d565b9392505050565b60008083601f840112612fad57600080fd5b50813567ffffffffffffffff811115612fc557600080fd5b602083019150836020828501011115612fdd57600080fd5b9250929050565b600080600080600060808688031215612ffc57600080fd5b8535945060208601359350604086013567ffffffffffffffff81111561302157600080fd5b61302d88828901612f9b565b9094509250613040905060608701612f5d565b90509295509295909350565b6000806040838503121561305f57600080fd5b50508035926020909101359150565b80151581146120ba57600080fd5b8035612f748161306e565b6000806040838503121561309a57600080fd5b6130a383612f5d565b915060208301356130b38161306e565b809150509250929050565b6000602082840312156130d057600080fd5b5035919050565b815181526020808301516101608301916130fb908401826001600160a01b03169052565b50604083015161311660408401826001600160a01b03169052565b50606083015161313160608401826001600160a01b03169052565b506080830151613146608084018260ff169052565b5060a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401518184015250610140808401516126f7828501826001600160a01b03169052565b6000806000606084860312156131ad57600080fd5b83359250602084013591506131c460408501612f5d565b90509250925092565b803560ff81168114612f7457600080fd5b600080600080608085870312156131f457600080fd5b84359350613204602086016131cd565b93969395505050506040820135916060013590565b6020808252825182820181905260009190848201906040850190845b8181101561325a5783516001600160a01b031683529284019291840191600101613235565b50909695505050505050565b6000806040838503121561327957600080fd5b61328283612f5d565b915061329060208401612f5d565b90509250929050565b6000806000806000608086880312156132b157600080fd5b853594506132c160208701612f5d565b935060408601359250606086013567ffffffffffffffff8111156132e457600080fd5b6132f088828901612f9b565b969995985093965092949392505050565b6000806000806060858703121561331757600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561333c57600080fd5b61334887828801612f9b565b95989497509550505050565b60008060008060008060008060008060006101408c8e03121561337657600080fd5b8b359a5061338660208d01612f5d565b995061339460408d01612f5d565b98506133a260608d01612f5d565b97506133b060808d016131cd565b965060a08c0135955060c08c0135945060e08c013567ffffffffffffffff808211156133db57600080fd5b818e0191508e601f8301126133ef57600080fd5b8135818111156133fe57600080fd5b8f60208260051b850101111561341357600080fd5b60208301965080955050505061342c6101008d01612f5d565b915061343b6101208d0161307c565b90509295989b509295989b9093969950565b6000806040838503121561346057600080fd5b61346983612f5d565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156109d5576109d5613477565b60ff81811683821601908111156109d5576109d5613477565b80820281158282048414176109d5576109d5613477565b634e487b7160e01b600052601260045260246000fd5b6000826134f5576134f56134d0565b500490565b818103818111156109d5576109d5613477565b60008261351c5761351c6134d0565b500690565b60006001820161353357613533613477565b5060010190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561356257600080fd5b8151612f948161306e565b60006020828403121561357f57600080fd5b5051919050565b87815286602082015260018060a01b038616604082015284606082015283608082015260c060a08201528160c0820152818360e0830137600081830160e090810191909152601f909201601f191601019695505050505050565b6000825160005b8181101561360157602081860181015185830152016135e7565b50600092019182525091905056fea2646970667358221220821177e9e0558a64b619a937b584174ae65a826872de00f2c0df7e654fdc832f64736f6c63430008130033000000000000000000000000b0552b6860ce5c0202976db056b5e3cc4f9cc76500000000000000000000000099edb5782da5d799dd16a037fdbc00a1494b9ead000000000000000000000000b0552b6860ce5c0202976db056b5e3cc4f9cc7650000000000000000000000000000000000000000000000000000000000093a800000000000000000000000000000000000000000000000000000000000000002

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061027f5760003560e01c80638070c5031161015c578063b0e1c1e1116100ce578063d598215b11610087578063d598215b1461083d578063ddca3f4314610850578063df4c3d1014610859578063eb8203121461087c578063f1efe24c146108a5578063fffa86fc146108b857600080fd5b8063b0e1c1e1146107bb578063b956358c146107ce578063c415b95c146107e1578063ce35de95146107f4578063d38bfff414610817578063d49466a81461082a57600080fd5b8063990161421161012057806399016142146106e357806399e9d29e146106f65780639dd535971461075b578063a42dce801461076e578063a4bb094614610781578063ac4746ab1461079457600080fd5b80638070c503146105865780638bc8407a146105995780638e3c282b146105ac5780638e57daa7146105e557806398bf6de81461060557600080fd5b806352aed578116101f557806366629f12116101b957806366629f12146104fe57806369fe0e2d1461052f5780636dbb5011146105425780636fb08df2146105555780637274e30d14610575578063766718081461057e57600080fd5b806352aed578146104305780635598f8cc1461047857806355b88ff6146104985780635aa6e675146104cb5780635dda2d63146104de57600080fd5b80631ec72172116102475780631ec7217214610325578063238efcbc1461033a5780632a0621d71461034257806338013f021461034c5780633bbed4a01461038b5780633ce9772e146103c857600080fd5b806303f17e561461028457806309066d7c146102b75780630f62accf146102ca57806317f3a722146102d25780631ac5c6ee1461031b575b600080fd5b6102a4610292366004612f79565b60086020526000908152604090205481565b6040519081526020015b60405180910390f35b6102a46102c5366004612fe4565b6108cb565b6102a4603281565b6102e56102e036600461304c565b610959565b6040516102ae9190815160ff16815260208083015190820152604080830151908201526060918201519181019190915260800190565b6102a462dd7c0081565b610338610333366004613087565b6109db565b005b610338610a31565b6102a46224ea0081565b6103737f00000000000000000000000099edb5782da5d799dd16a037fdbc00a1494b9ead81565b6040516001600160a01b0390911681526020016102ae565b610338610399366004612f79565b33600090815260076020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b61040c6103d636600461304c565b600c602090815260009283526040808420909152908252902080546001820154600283015460039093015460ff90921692909184565b6040805160ff909516855260208501939093529183015260608201526080016102ae565b61044361043e36600461304c565b610a83565b6040516102ae919081518152602080830151908201526040808301519082015260609182015115159181019190915260800190565b61048b6104863660046130be565b610b01565b6040516102ae91906130d7565b6104bb6104a63660046130be565b600a6020526000908152604090205460ff1681565b60405190151581526020016102ae565b600054610373906001600160a01b031681565b6102a46104ec3660046130be565b600d6020526000908152604090205481565b6102a461050c366004613198565b600e60209081526000938452604080852082529284528284209052825290205481565b61033861053d3660046130be565b610c28565b6103386105503660046131de565b610c81565b6105686105633660046130be565b610fe7565b6040516102ae9190613219565b6102a460055481565b6102a4611001565b600154610373906001600160a01b031681565b6103386105a7366004613266565b61103d565b6105d37f000000000000000000000000000000000000000000000000000000000000000281565b60405160ff90911681526020016102ae565b6102a46105f33660046130be565b60106020526000908152604090205481565b6106826106133660046130be565b6009602081905260009182526040909120805460018201546002830154600384015460048501546005860154600687015460078801546008890154989099015496986001600160a01b03968716989587169787861697600160a01b90960460ff1696949593949293919291168b565b604080519b8c526001600160a01b039a8b1660208d0152988a16988b019890985295881660608a015260ff909416608089015260a088019290925260c087015260e086015261010085015261012084015216610140820152610160016102ae565b6102a46106f1366004613299565b611096565b61073961070436600461304c565b600b60209081526000928352604080842090915290825290208054600182015460028301546003909301549192909160ff1684565b60408051948552602085019390935291830152151560608201526080016102ae565b6102a461076936600461304c565b6111c9565b61033861077c366004612f79565b61122c565b6102a461078f366004613301565b6112a0565b6102a47f0000000000000000000000000000000000000000000000000000000000093a8081565b6103386107c93660046130be565b6113b0565b6102a46107dc366004613354565b61150d565b600354610373906001600160a01b031681565b6104bb610802366004612f79565b60066020526000908152604090205460ff1681565b610338610825366004612f79565b61197a565b61033861083836600461344d565b6119ee565b600254610373906001600160a01b031681565b6102a460045481565b6104bb6108673660046130be565b600f6020526000908152604090205460ff1681565b61037361088a366004612f79565b6007602052600090815260409020546001600160a01b031681565b6103386108b3366004612f79565b611a5e565b6103386108c636600461304c565b611ad2565b60003068929eee149b4bd2126854036108ec5763ab143c066000526004601cfd5b3068929eee149b4bd21268556109436040518060c00160405280888152602001336001600160a01b03168152602001846001600160a01b031681526020018781526020016000815260200160008152508585611db3565b3868929eee149b4bd21268559695505050505050565b6109876040518060800160405280600060ff1681526020016000815260200160008152602001600081525090565b506000828152600c602090815260408083208484528252918290208251608081018452815460ff16815260018201549281019290925260028101549282019290925260039091015460608201525b92915050565b6000546001600160a01b03163314610a0657604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b6001546001600160a01b03163314610a5c57604051630c39d07960e01b815260040160405180910390fd5b60018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b610ab060405180608001604052806000815260200160008152602001600081526020016000151581525090565b506000918252600b60209081526040808420928452918152918190208151608081018352815481526001820154938101939093526002810154918301919091526003015460ff161515606082015290565b610b856040518061016001604052806000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600060ff168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b506000908152600960208181526040928390208351610160810185528154815260018201546001600160a01b0390811693820193909352600282015483169481019490945260038101548083166060860152600160a01b900460ff166080850152600481015460a0850152600581015460c0850152600681015460e085015260078101546101008501526008810154610120850152909101541661014082015290565b6000546001600160a01b03163314610c5357604051630c39d07960e01b815260040160405180910390fd5b67016345785d8a0000811115610c7c5760405163b68600c760e01b815260040160405180910390fd5b600455565b3068929eee149b4bd212685403610ca05763ab143c066000526004601cfd5b3068929eee149b4bd212685583610cb681612067565b6000858152600a6020526040902054859060ff1615610ce857604051630e1bf69160e01b815260040160405180910390fd5b6000610cf2611001565b90506001610d0088836111c9565b11610d1e57604051630e1bf69160e01b815260040160405180910390fd5b600087815260096020526040902060078101548210801590610d5d57506000888152600b6020908152604080832085845290915290206003015460ff16155b15610d7b5760405163c9936a5360e01b815260040160405180910390fd5b610da57f0000000000000000000000000000000000000000000000000000000000093a808361348d565b6000898152600c602090815260408083208484528252918290208251608081018452815460ff16815260018201549281019290925260028101549282019290925260039091015460608201529092508615610e14576003820154610e14906001600160a01b031633308a6120bd565b602081015115610eb4576040518060800160405280898360000151610e3991906134a0565b60ff168152602001888360200151610e51919061348d565b815260200160008811610e68578260400151610e6a565b875b8152602001610e9c7f0000000000000000000000000000000000000000000000000000000000093a8060ff8c166134b9565b8360600151610eab919061348d565b90529050610f53565b6040518060800160405280898460030160149054906101000a900460ff16610edc91906134a0565b60ff168152602001888460050154610ef4919061348d565b815260200160008811610f0b578360040154610f0d565b875b8152602001610f3f7f0000000000000000000000000000000000000000000000000000000000093a8060ff8c166134b9565b8460080154610f4e919061348d565b905290505b6000898152600c602090815260408083208684528252918290208351815460ff191660ff909116178155838201516001820155838301516002820155606084015160039091015581518b81529081018590527fa8bf14cbd1773eaebffd457f5e6a2badb14741d5e87b85eb41e4adb86080ac0c910160405180910390a150505050503868929eee149b4bd212685550505050565b60008181526010602052604090206060906109d590612111565b60007f0000000000000000000000000000000000000000000000000000000000093a8061102e81426134e6565b61103891906134b9565b905090565b6000546001600160a01b0316331461106857604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b03918216600090815260076020526040902080546001600160a01b03191691909216179055565b60003068929eee149b4bd2126854036110b75763ab143c066000526004601cfd5b3068929eee149b4bd21268556001600160a01b03851660009081526006602052604090205460ff16801561110357506001600160a01b0385811660009081526007602052604090205416155b1561112157604051631128f5c960e01b815260040160405180910390fd5b6001600160a01b0385811660009081526007602052604081205490911615611163576001600160a01b0380871660009081526007602052604090205416611165565b855b90506111b26040518060c00160405280898152602001886001600160a01b03168152602001836001600160a01b031681526020018781526020016000815260200160008152508585611db3565b3868929eee149b4bd2126855979650505050505050565b6000828152600960205260408120600881015483106111e9576000611224565b7f0000000000000000000000000000000000000000000000000000000000093a8083826008015461121a91906134fa565b61122491906134e6565b949350505050565b6000546001600160a01b0316331461125757604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b03811661127e5760405163538ba4f960e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60003068929eee149b4bd2126854036112c15763ab143c066000526004601cfd5b3068929eee149b4bd21268556000858152600a6020526040902054859060ff16156112ff57604051630e1bf69160e01b815260040160405180910390fd5b85854281118061131f575060008281526009602052604090206007015481105b8061133b57506000828152600960205260409020600801548110155b8061136e575061136b7f0000000000000000000000000000000000000000000000000000000000093a808261350d565b15155b1561138c576040516327a9565960e01b815260040160405180910390fd5b611398888888886121e6565b3868929eee149b4bd212685598975050505050505050565b6000818152600a6020526040902054819060ff16156113e257604051630e1bf69160e01b815260040160405180910390fd5b3068929eee149b4bd2126854036114015763ab143c066000526004601cfd5b3068929eee149b4bd212685560008281526009602052604081206008810154909142916114329062dd7c009061348d565b905060006114436224ea008361348d565b600285015460078601549192506001600160a01b03169084101561147d5761146a87612067565b611478878660070154612300565b6114d9565b8284101561149e5760405163966c987560e01b815260040160405180910390fd5b818410156114bd576114af87612067565b6114788786600801546123dc565b6114cb8786600801546123dc565b506003546001600160a01b03165b600585015460038601546114f89189916001600160a01b03168461244d565b50505050503868929eee149b4bd21268555050565b60003068929eee149b4bd21268540361152e5763ab143c066000526004601cfd5b3068929eee149b4bd21268557f000000000000000000000000000000000000000000000000000000000000000260ff168860ff1610156115815760405163b68600c760e01b815260040160405180910390fd5b85158061158c575086155b156115aa576040516360a6332360e01b815260040160405180910390fd5b6001600160a01b03891615806115c757506001600160a01b038b16155b156115e55760405163538ba4f960e01b815260040160405180910390fd5b60328411156116075760405163b68600c760e01b815260040160405180910390fd5b883b600081900361162b5760405163684cae7960e11b815260040160405180910390fd5b6116378a33308a6120bd565b600580549250600061164884613521565b9091555060007f0000000000000000000000000000000000000000000000000000000000093a80611677611001565b611681919061348d565b90506040518061016001604052808f81526020018e6001600160a01b031681526020018d6001600160a01b031681526020018c6001600160a01b031681526020018b60ff1681526020018a8152602001898152602001600081526020018281526020017f0000000000000000000000000000000000000000000000000000000000093a808c60ff1661171391906134b9565b61171d908461348d565b81526001600160a01b03808816602092830152600086815260098084526040918290208551815593850151600180860180549286166001600160a01b0319938416179055928601516002860180549186169183169190911790556060860151600386018054608089015160ff908116600160a01b026001600160a81b03199092169388169390931717905560a0870151600487015560c0870151600587015560e087015160068701556101008701516007870155610120870151600887015561014090960151949091018054949093169316929092179055611803918a91908d166124d1565b6000848152600b6020908152604080832085845282528083209390935585825260109052908120905b878110156118b05760008989838181106118485761184861353a565b905060200201602081019061185d9190612f79565b6001600160a01b03161461189e5761189c8989838181106118805761188061353a565b90506020020160208101906118959190612f79565b83906124f7565b505b806118a881613521565b91505061182c565b5084600f600086815260200190815260200160002060006101000a81548160ff0219169083151502179055507f0e291713fc4cb1bcf9276bc9ae54317736576d5353a44151e2e31c191b1ee62a848f8f8f8f8f8f60405161195497969594939291909687526001600160a01b039586166020880152938516604087015291909316606085015260ff92909216608084015260a083019190915260c082015260e00190565b60405180910390a15050503868929eee149b4bd21268559b9a5050505050505050505050565b6000546001600160a01b031633146119a557604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b0381166119cc5760405163538ba4f960e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314611a1957604051630c39d07960e01b815260040160405180910390fd5b67016345785d8a0000811115611a425760405163b68600c760e01b815260040160405180910390fd5b6001600160a01b03909116600090815260086020526040902055565b6000546001600160a01b03163314611a8957604051630c39d07960e01b815260040160405180910390fd5b6001600160a01b038116611ab05760405163538ba4f960e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b3068929eee149b4bd212685403611af15763ab143c066000526004601cfd5b3068929eee149b4bd21268556000828152600a6020526040902054829060ff1615611b2f57604051630e1bf69160e01b815260040160405180910390fd5b6000611b39611001565b905082600003611b5c576040516360a6332360e01b815260040160405180910390fd5b6001611b6885836111c9565b11611b8657604051630e1bf69160e01b815260040160405180910390fd5b6000848152600c602090815260408083208484528252918290208251608081018452815460ff168152600182015492810183905260028201549381019390935260030154606083015215801590611bfa57506000858152600b6020908152604080832085845290915290206003015460ff16155b15611c185760405163c9936a5360e01b815260040160405180910390fd5b611c427f0000000000000000000000000000000000000000000000000000000000093a808361348d565b6000868152600960209081526040808320600c83528184208585528352928190208151608081018352815460ff1681526001820154938101939093526002810154918301919091526003908101546060830152820154929450925090611cb3906001600160a01b03163330886120bd565b602082015115611cd7578482602001818151611ccf919061348d565b905250611d22565b60408051608081019091526003820154600160a01b900460ff16815260058201546020820190611d0890889061348d565b815260200182600401548152602001826008015481525091505b6000868152600c602090815260408083208684528252918290208451815460ff191660ff909116178155848201516001820155848301516002820155606085015160039091015581518881529081018590527fa8bf14cbd1773eaebffd457f5e6a2badb14741d5e87b85eb41e4adb86080ac0c910160405180910390a1505050503868929eee149b4bd21268555050565b82516000818152600a602052604081205490919060ff1615611de857604051630e1bf69160e01b815260040160405180910390fd5b8451606086015142811180611e0d575060008281526009602052604090206007015481105b80611e2957506000828152600960205260409020600801548110155b80611e5c5750611e597f0000000000000000000000000000000000000000000000000000000000093a808261350d565b15155b15611e7a576040516327a9565960e01b815260040160405180910390fd5b865160208089015160608a0151600084815260109093526040832091929091611ea3908461264c565b6000858152600f602052604090205490915060ff168015611ec2575080155b15611ee0576040516307957bbf60e11b815260040160405180910390fd5b6000848152600f602052604090205460ff16158015611efc5750805b15611f1a5760405163e132c7cd60e01b815260040160405180910390fd5b611f2e8b600001518c606001518c8c6121e6565b60608c0152611f3c8b6126ff565b611f495760009750612059565b611f528b61285b565b8c6080018d60a00182815250828152505050600960008c600001518152602001908152602001600020600501548b60a001518c60800151600d60008f60000151815260200190815260200160002054611fab919061348d565b611fb5919061348d565b1115611fd45760405163506d8cdf60e11b815260040160405180910390fd5b611fdd8b6129ca565b611fe68b612a4e565b8a602001516001600160a01b03168b600001517f318e0a24a7fc05b12e358902d9d58475434a01768f87a4319fb35dc5b533e9868d608001518e60a001518f60600151604051612049939291909283526020830191909152604082015260600190565b60405180910390a38a6080015197505b505050505050509392505050565b6000818152600960205260409020600201546001600160a01b0316331480159061209c57506002546001600160a01b03163314155b156120ba5760405163fabbbc6760e01b815260040160405180910390fd5b50565b60405181606052826040528360601b602c526323b872dd60601b600c52602060006064601c6000895af13d15600160005114171661210357637939f4246000526004601cfd5b600060605260405250505050565b63978aab926004526000818152602481206060915068fbb67fda52d4bfb8bf81548060a01b60a01c6040519450846020018260601c92508383141583028152816121a057821561219b57600191508185015460601c9250821561219b578284141590920260208301525060028381015460601c91821561219b576003915083831415830260408201525b6121d0565b600191821c915b828110156121ce578581015460601c858114158102600583901b84015293506001016121a7565b505b8186528160051b81016040525050505050919050565b6000848152600b602090815260408083208684529091528120600381015460ff16156122155784915050611224565b61221f8686612300565b60008681526009602052604090206007015461225c907f0000000000000000000000000000000000000000000000000000000000093a809061348d565b851061226c5761226c86866123dc565b600061227887876111c9565b9050600061228588612aa7565b90506000821161229557806122a1565b6122a1816001846124d1565b83556122b08888858989612aca565b600283015483546122c191906134fa565b600089815260096020526040812060060180549091906122e290849061348d565b90915550505050600301805460ff1916600117905550919392505050565b6000828152600c602090815260408083208484528252918290208251608081018452815460ff1681526001820154928101839052600282015493810193909352600301546060830152156123d75760008381526009602090815260409182902060608401516008820155835160038201805460ff909216600160a01b0260ff60a01b199092169190911790558383015160048201558382015160058201558251868152918201859052917fa416776236c15a5c5398bdb783dfe811a1723512b5fb8914aeb21873defa1872910160405180910390a1505b505050565b6000828152600b60205260408120816124157f0000000000000000000000000000000000000000000000000000000000093a80856134fa565b81526020810191909152604001600020600381015490915060ff166123d75760405163c9936a5360e01b815260040160405180910390fd5b6000848152600d602052604081205461246690856134fa565b9050612473838383612c9a565b6000858152600d60209081526040808320879055600a825291829020805460ff1916600117905590518681527f5e6eb33a418de5dbbc17f989f7ae362cdfbb1748c5d603137c767027a354edbc910160405180910390a15050505050565b828202831584820484141782026124f05763ad251c276000526004601cfd5b0492915050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be1983016125345763f5a267f16000526004601cfd5b826125465768fbb67fda52d4bfb8bf92505b80546bffffffffffffffffffffffff8116826020528061260e578160601c80612579578560601b84556001945050612643565b8581036125865750612643565b600184015460601c806125a7578660601b6001860155600195505050612643565b8681036125b5575050612643565b600285015460601c806125d7578760601b600287015560019650505050612643565b8781036125e657505050612643565b6000928352604080842060019055918352818320600290558252902060039055506007908117905b8460005260406000208054612641578160011c91508560601b828501558160010181558260020184556001945050612643565b505b50505092915050565b63978aab926004526000828152602481206001600160a01b03929092169168fbb67fda52d4bfb8be1983016126895763f5a267f16000526004601cfd5b8261269b5768fbb67fda52d4bfb8bf92505b80546bffffffffffffffffffffffff81166126e45760019250838160601c03156126f757600182015460601c84146126f757600282015460601c84146126f757600092506126f7565b8160205283600052604060002054151592505b505092915050565b8051600090815260096020908152604080832091840151600183015460608601519251635817dca560e11b81526001600160a01b0392831660048201529082166024820152604481019290925283917f00000000000000000000000099edb5782da5d799dd16a037fdbc00a1494b9ead9091169063b02fb94a90606401602060405180830381865afa158015612799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bd9190613550565b905060004262dd7c0084600801546127d5919061348d565b86516000908152600e6020908152604080832060608b015184528252808320828b01516001600160a01b0316845290915281205492909111925090158061283c575085516000908152600b6020908152604080832060608a01518452909152902060010154155b90508280156128485750815b80156128515750805b9695505050505050565b8051600090815260096020908152604080832091840151600183015460608601519251630520fe4160e31b81526001600160a01b0392831660048201529082166024820152604481019290925283929183917f00000000000000000000000099edb5782da5d799dd16a037fdbc00a1494b9ead1690632907f20890606401602060405180830381865afa1580156128f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291a919061356d565b85516000908152600b6020908152604080832060608a01518452909152902060010154909150612954908290670de0b6b3a76400006124d1565b60028301546001600160a01b0316600090815260086020526040812054919550906129815760045461299f565b60028301546001600160a01b03166000908152600860205260409020545b90506129b48582670de0b6b3a76400006124d1565b93506129c084866134fa565b9450505050915091565b8060a0015181608001516129de919061348d565b81516000908152600e60209081526040808320606086015184528252808320828601516001600160a01b0316845290915290205560a08101516080820151612a26919061348d565b81516000908152600d602052604081208054909190612a4690849061348d565b909155505050565b805160009081526009602052604090819020600301549082015160808301516001600160a01b0390921691612a84918391612c9a565b60035460a0830151612aa39183916001600160a01b0390911690612c9a565b5050565b600081815260096020526040812060068101546005909101546109d591906134fa565b6000612ad68686612ce0565b905080600003612aed575082546002840155612c93565b60008681526009602052604081208554909190612b1390670de0b6b3a7640000856124d1565b90508160040154811115612c8b575060048101546000612b3c8285670de0b6b3a76400006124d1565b8754612b4891906134fa565b60098401549091506001600160a01b03168015612c6e576003840154612b78906001600160a01b03168284612c9a565b806001600160a01b0316631406610660e01b8b86600001548760030160009054906101000a90046001600160a01b03168d878d8d604051602401612bc29796959493929190613586565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c0091906135e0565b6000604051808303816000865af19150503d8060008114612c3d576040519150601f19603f3d011682016040523d82523d6000602084013e612c42565b606091505b50505060008a8152600d602052604081208054849290612c6390849061348d565b90915550612c889050565b81886002016000828254612c82919061348d565b90915550505b50505b600186015550505b5050505050565b816014528060345263a9059cbb60601b60005260206000604460106000875af13d156001600051141716612cd6576390b8ec186000526004601cfd5b6000603452505050565b6000828152601060209081526040808320600990925280832060010154905163085a4a3d60e31b81526001600160a01b0391821660048201526024810185905283917f00000000000000000000000099edb5782da5d799dd16a037fdbc00a1494b9ead16906342d251e890604401602060405180830381865afa158015612d6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d8f919061356d565b90506000805b612d9e84612eb1565b811015612e85576001600160a01b037f00000000000000000000000099edb5782da5d799dd16a037fdbc00a1494b9ead16632907f208612dde8684612f03565b60008a8152600960205260409081902060010154905160e084901b6001600160e01b03191681526001600160a01b0392831660048201529116602482015260448101899052606401602060405180830381865afa158015612e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e67919061356d565b612e71908361348d565b915080612e7d81613521565b915050612d95565b506000868152600f602052604090205460ff1615612ea75792506109d5915050565b61285181836134fa565b63978aab9260045260008181526024812080548060a01b60a01c8060011c9350808260601c1517612efb57600193508383015415612efb57600293508383015415612efb57600393505b505050919050565b63978aab926004526000828152602481208281015460601c915068fbb67fda52d4bfb8bf82141582029150612f3784612eb1565b8310612f5657604051634e23d03560e01b815260040160405180910390fd5b5092915050565b80356001600160a01b0381168114612f7457600080fd5b919050565b600060208284031215612f8b57600080fd5b612f9482612f5d565b9392505050565b60008083601f840112612fad57600080fd5b50813567ffffffffffffffff811115612fc557600080fd5b602083019150836020828501011115612fdd57600080fd5b9250929050565b600080600080600060808688031215612ffc57600080fd5b8535945060208601359350604086013567ffffffffffffffff81111561302157600080fd5b61302d88828901612f9b565b9094509250613040905060608701612f5d565b90509295509295909350565b6000806040838503121561305f57600080fd5b50508035926020909101359150565b80151581146120ba57600080fd5b8035612f748161306e565b6000806040838503121561309a57600080fd5b6130a383612f5d565b915060208301356130b38161306e565b809150509250929050565b6000602082840312156130d057600080fd5b5035919050565b815181526020808301516101608301916130fb908401826001600160a01b03169052565b50604083015161311660408401826001600160a01b03169052565b50606083015161313160608401826001600160a01b03169052565b506080830151613146608084018260ff169052565b5060a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401518184015250610140808401516126f7828501826001600160a01b03169052565b6000806000606084860312156131ad57600080fd5b83359250602084013591506131c460408501612f5d565b90509250925092565b803560ff81168114612f7457600080fd5b600080600080608085870312156131f457600080fd5b84359350613204602086016131cd565b93969395505050506040820135916060013590565b6020808252825182820181905260009190848201906040850190845b8181101561325a5783516001600160a01b031683529284019291840191600101613235565b50909695505050505050565b6000806040838503121561327957600080fd5b61328283612f5d565b915061329060208401612f5d565b90509250929050565b6000806000806000608086880312156132b157600080fd5b853594506132c160208701612f5d565b935060408601359250606086013567ffffffffffffffff8111156132e457600080fd5b6132f088828901612f9b565b969995985093965092949392505050565b6000806000806060858703121561331757600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561333c57600080fd5b61334887828801612f9b565b95989497509550505050565b60008060008060008060008060008060006101408c8e03121561337657600080fd5b8b359a5061338660208d01612f5d565b995061339460408d01612f5d565b98506133a260608d01612f5d565b97506133b060808d016131cd565b965060a08c0135955060c08c0135945060e08c013567ffffffffffffffff808211156133db57600080fd5b818e0191508e601f8301126133ef57600080fd5b8135818111156133fe57600080fd5b8f60208260051b850101111561341357600080fd5b60208301965080955050505061342c6101008d01612f5d565b915061343b6101208d0161307c565b90509295989b509295989b9093969950565b6000806040838503121561346057600080fd5b61346983612f5d565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156109d5576109d5613477565b60ff81811683821601908111156109d5576109d5613477565b80820281158282048414176109d5576109d5613477565b634e487b7160e01b600052601260045260246000fd5b6000826134f5576134f56134d0565b500490565b818103818111156109d5576109d5613477565b60008261351c5761351c6134d0565b500690565b60006001820161353357613533613477565b5060010190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561356257600080fd5b8151612f948161306e565b60006020828403121561357f57600080fd5b5051919050565b87815286602082015260018060a01b038616604082015284606082015283608082015260c060a08201528160c0820152818360e0830137600081830160e090810191909152601f909201601f191601019695505050505050565b6000825160005b8181101561360157602081860181015185830152016135e7565b50600092019182525091905056fea2646970667358221220821177e9e0558a64b619a937b584174ae65a826872de00f2c0df7e654fdc832f64736f6c63430008130033

Deployed Bytecode Sourcemap

111015:39312:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113007:53;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;529:25:1;;;517:2;502:18;113007:53:0;;;;;;;;121096:493;;;;;;:::i;:::-;;:::i;111655:55::-;;111708:2;111655:55;;146476:172;;;;;;:::i;:::-;;:::i;:::-;;;;;;2110:13:1;;2125:4;2106:24;2088:43;;2187:4;2175:17;;;2169:24;2147:20;;;2140:54;2250:4;2238:17;;;2232:24;2210:20;;;2203:54;2313:4;2301:17;;;2295:24;2273:20;;;2266:54;;;;2075:3;2060:19;;1875:451;111404:54:0;;111450:8;111404:54;;147868:140;;;;;;:::i;:::-;;:::i;:::-;;150123:201;;;:::i;111534:53::-;;111580:7;111534:53;;111937:31;;;;;;;;-1:-1:-1;;;;;3180:32:1;;;3162:51;;3150:2;3135:18;111937:31:0;3016:203:1;149009:105:0;;;;;;:::i;:::-;149082:10;149071:22;;;;:10;:22;;;;;:35;;-1:-1:-1;;;;;;149071:35:0;-1:-1:-1;;;;;149071:35:0;;;;;;;;;;149009:105;113491:82;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3481:4:1;3469:17;;;3451:36;;3518:2;3503:18;;3496:34;;;;3546:18;;;3539:34;3604:2;3589:18;;3582:34;3438:3;3423:19;113491:82:0;3224:398:1;147168:164:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;3840:13:1;;3822:32;;3910:4;3898:17;;;3892:24;3870:20;;;3863:54;3973:4;3961:17;;;3955:24;3933:20;;;3926:54;4050:4;4038:17;;;4032:24;4025:32;4018:40;3996:20;;;3989:70;;;;3809:3;3794:19;;3627:438;146122:129:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;113200:48::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;5634:14:1;;5627:22;5609:41;;5597:2;5582:18;113200:48:0;5469:187:1;112186:25:0;;;;;-1:-1:-1;;;;;112186:25:0;;;113630:59;;;;;;:::i;:::-;;;;;;;;;;;;;;113769:96;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;148429:134;;;;;;:::i;:::-;;:::i;137180:2416::-;;;;;;:::i;:::-;;:::i;146819:159::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;112552:28::-;;;;;;147423:125;;;:::i;112264:31::-;;;;;-1:-1:-1;;;;;112264:31:0;;;149269:136;;;;;;:::i;:::-;;:::i;111769:38::-;;;;;;;;7641:4:1;7629:17;;;7611:36;;7599:2;7584:18;111769:38:0;7469:184:1;114064:76:0;;;;;;:::i;:::-;;;;;;;;;;;;;;113103:48;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;113103:48:0;;;;;;;;;;;;-1:-1:-1;;;113103:48:0;;;;;;;;;;;;;;;;;;;;;;8082:25:1;;;-1:-1:-1;;;;;8181:15:1;;;8176:2;8161:18;;8154:43;8233:15;;;8213:18;;;8206:43;;;;8285:15;;;8280:2;8265:18;;8258:43;8350:4;8338:17;;;8332:3;8317:19;;8310:46;8134:3;8372:19;;8365:35;;;;8431:3;8416:19;;8409:35;8475:3;8460:19;;8453:35;8519:3;8504:19;;8497:35;8563:3;8548:19;;8541:35;8613:16;8607:3;8592:19;;8585:45;8069:3;8054:19;113103:48:0;7658:978:1;119971:773:0;;;;;;:::i;:::-;;:::i;113308:72::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9491:25:1;;;9547:2;9532:18;;9525:34;;;;9575:18;;;9568:34;9645:14;9638:22;9633:2;9618:18;;9611:50;9478:3;9463:19;113308:72:0;9266:401:1;145693:284:0;;;;;;:::i;:::-;;:::i;149521:184::-;;;;;;:::i;:::-;;:::i;126856:299::-;;;;;;:::i;:::-;;:::i;111858:37::-;;;;;141880:1464;;;;;;:::i;:::-;;:::i;134117:2729::-;;;;;;:::i;:::-;;:::i;112433:27::-;;;;;-1:-1:-1;;;;;112433:27:0;;;112831:43;;;;;;:::i;:::-;;;;;;;;;;;;;;;;149833:203;;;;;;:::i;:::-;;:::i;148716:183::-;;;;;;:::i;:::-;;:::i;112372:21::-;;;;;-1:-1:-1;;;;;112372:21:0;;;112491:18;;;;;;113940:45;;;;;;:::i;:::-;;;;;;;;;;;;;;;;112912;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;112912:45:0;;;148104:236;;;;;;:::i;:::-;;:::i;139781:1997::-;;;;;;:::i;:::-;;:::i;121096:493::-;121247:15;78830:9;78805:22;78799:29;78796:44;78793:161;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41;121287:294:::1;121308:239;;;;;;;;121349:10;121308:239;;;;121387:10;-1:-1:-1::0;;;;;121308:239:0::1;;;;;121426:8;-1:-1:-1::0;;;;;121308:239:0::1;;;;;121460:5;121308:239;;;;121499:1;121308:239;;;;121530:1;121308:239;;::::0;121562:8:::1;;121287:6;:294::i;:::-;79141:10:::0;79117:22;79110:42;121280:301;121096:493;-1:-1:-1;;;;;;121096:493:0:o;146476:172::-;146560:22;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;146560:22:0;-1:-1:-1;146602:31:0;;;;:19;:31;;;;;;;;:38;;;;;;;;;146595:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;146476:172;;;;;:::o;147868:140::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;-1:-1:-1;;;;;147964:21:0;;;::::1;;::::0;;;:11:::1;:21;::::0;;;;:36;;-1:-1:-1;;147964:36:0::1;::::0;::::1;;::::0;;;::::1;::::0;;147868:140::o;150123:201::-;150189:16;;-1:-1:-1;;;;;150189:16:0;150175:10;:30;150171:65;;150214:22;;-1:-1:-1;;;150214:22:0;;;;;;;;;;;150171:65;150260:16;;;;150247:29;;-1:-1:-1;;;;;;150247:29:0;;;-1:-1:-1;;;;;150260:16:0;;150247:29;;;;150287;;;150123:201::o;147168:164::-;147254:13;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;147254:13:0;-1:-1:-1;147287:30:0;;;;:18;:30;;;;;;;;:37;;;;;;;;;;147280:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;147168:164::o;146122:129::-;146184:15;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;146184:15:0;-1:-1:-1;146219:24:0;;;;:12;:24;;;;;;;;;146212:31;;;;;;;;;;;;;;;-1:-1:-1;;;;;146212:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;146212:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;146122:129::o;148429:134::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;148505:5:::1;148498:4;:12;148494:40;;;148519:15;;-1:-1:-1::0;;;148519:15:0::1;;;;;;;;;;;148494:40;148545:3;:10:::0;148429:134::o;137180:2416::-;78830:9;78805:22;78799:29;78796:44;78793:161;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41;137385:10:::1;118330:30;118349:10;118330:18;:30::i;:::-;118092:28:::2;::::0;;;:16:::2;:28;::::0;;;;;137407:10;;118092:28:::2;;118088:57;;;118129:16;;-1:-1:-1::0;;;118129:16:0::2;;;;;;;;;;;118088:57;137430:13:::3;137446:14;:12;:14::i;:::-;137430:30;;137564:1;137522:38;137542:10;137554:5;137522:19;:38::i;:::-;:43;137518:72;;137574:16;;-1:-1:-1::0;;;137574:16:0::3;;;;;;;;;;;137518:72;137636:25;137664:24:::0;;;:12:::3;:24;::::0;;;;137705:23:::3;::::0;::::3;::::0;:32;-1:-1:-1;137705:32:0;::::3;::::0;:82:::3;;-1:-1:-1::0;137742:30:0::3;::::0;;;:18:::3;:30;::::0;;;;;;;:37;;;;;;;;:45:::3;;::::0;::::3;;137741:46;137705:82;137701:137;;;137811:15;;-1:-1:-1::0;;;137811:15:0::3;;;;;;;;;;;137701:137;137891:21;137900:12;137891:21:::0;::::3;:::i;:::-;138001:38;138042:31:::0;;;:19:::3;:31;::::0;;;;;;;:38;;;;;;;;;138001:79;;::::3;::::0;::::3;::::0;;;;::::3;;::::0;;;;::::3;::::0;;;::::3;::::0;;;;::::3;::::0;::::3;::::0;;;;;;;;::::3;::::0;;::::3;::::0;;;;;137891:21;;-1:-1:-1;138157:22:0;;138153:265:::3;;138255:20;::::0;::::3;::::0;138196:210:::3;::::0;-1:-1:-1;;;;;138255:20:0::3;138300:10;138341:4;138373:17:::0;138196:32:::3;:210::i;:::-;138473:33;::::0;::::3;::::0;:38;138469:942:::3;;138546:415;;;;;;;;138632:15;138598;:31;;;:49;;;;:::i;:::-;138546:415;;;;;;138721:17;138685:15;:33;;;:53;;;;:::i;:::-;138546:415;;;;138794:1;138775:16;:20;:74;;138817:15;:32;;;138775:74;;;138798:16;138775:74;138546:415:::0;;::::3;;138914:30;138932:12;138914:30;::::0;::::3;;:::i;:::-;138882:15;:28;;;:63;;;;:::i;:::-;138546:415:::0;;138528:433;-1:-1:-1;138469:942:0::3;;;139012:387;;;;;;;;139091:15;139064:8;:24;;;;;;;;;;;;:42;;;;:::i;:::-;139012:387;;;;;;139173:17;139144:8;:26;;;:46;;;;:::i;:::-;139012:387;;;;139246:1;139227:16;:20;:67;;139269:8;:25;;;139227:67;;;139250:16;139227:67;139012:387:::0;;::::3;;139352:30;139370:12;139352:30;::::0;::::3;;:::i;:::-;139327:8;:21;;;:56;;;;:::i;:::-;139012:387:::0;;138994:405;-1:-1:-1;138469:942:0::3;139474:31;::::0;;;:19:::3;:31;::::0;;;;;;;:38;;;;;;;;;:56;;;;-1:-1:-1;;139474:56:0::3;;::::0;;::::3;;::::0;;;;::::3;::::0;-1:-1:-1;139474:56:0;::::3;::::0;;;::::3;::::0;::::3;::::0;::::3;::::0;::::3;::::0;::::3;::::0;::::3;::::0;;::::3;::::0;139548:40;;12510:25:1;;;12551:18;;;12544:34;;;139548:40:0::3;::::0;12483:18:1;139548:40:0::3;;;;;;;137419:2177;;;118371:1:::2;79030::::1;79141:10:::0;79117:22;79110:42;137180:2416;;;;:::o;146819:159::-;146928:33;;;;:21;:33;;;;;146892:16;;146928:42;;:40;:42::i;147423:125::-;147468:7;147528:12;147495:30;147528:12;147495:15;:30;:::i;:::-;:45;;;;:::i;:::-;147488:52;;147423:125;:::o;149269:136::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;-1:-1:-1;;;;;149364:20:0;;::::1;;::::0;;;:10:::1;:20;::::0;;;;:33;;-1:-1:-1;;;;;;149364:33:0::1;::::0;;;::::1;;::::0;;149269:136::o;119971:773::-;120121:15;78830:9;78805:22;78799:29;78796:44;78793:161;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41;-1:-1:-1;;;;;120209:20:0;::::1;;::::0;;;:11:::1;:20;::::0;;;;;::::1;;:57:::0;::::1;;;-1:-1:-1::0;;;;;;120233:19:0;;::::1;120264:1;120233:19:::0;;;:10:::1;:19;::::0;;;;;::::1;:33:::0;120209:57:::1;120205:89;;;120275:19;;-1:-1:-1::0;;;120275:19:0::1;;;;;;;;;;;120205:89;-1:-1:-1::0;;;;;120360:19:0;;::::1;120341:16;120360:19:::0;;;:10:::1;:19;::::0;;;;;120341:16;;120360:19:::1;:33:::0;:65:::1;;-1:-1:-1::0;;;;;120406:19:0;;::::1;;::::0;;;:10:::1;:19;::::0;;;;;::::1;120360:65;;;120396:7;120360:65;120341:84;;120445:291;120466:236;;;;;;;;120507:10;120466:236;;;;120545:7;-1:-1:-1::0;;;;;120466:236:0::1;;;;;120581:8;-1:-1:-1::0;;;;;120466:236:0::1;;;;;120615:5;120466:236;;;;120654:1;120466:236;;;;120685:1;120466:236;;::::0;120717:8:::1;;120445:6;:291::i;:::-;79141:10:::0;79117:22;79110:42;120438:298;119971:773;-1:-1:-1;;;;;;;119971:773:0:o;145693:284::-;145778:19;145838:24;;;:12;:24;;;;;145887:21;;;;:29;-1:-1:-1;145887:82:0;;145968:1;145887:82;;;145953:12;145944:5;145920:8;:21;;;:29;;;;:::i;:::-;145919:46;;;;:::i;:::-;145873:96;145693:284;-1:-1:-1;;;;145693:284:0:o;149521:184::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;-1:-1:-1;;;;;149608:27:0;::::1;149604:54;;149644:14;;-1:-1:-1::0;;;149644:14:0::1;;;;;;;;;;;149604:54;149669:12;:28:::0;;-1:-1:-1;;;;;;149669:28:0::1;-1:-1:-1::0;;;;;149669:28:0;;;::::1;::::0;;;::::1;::::0;;149521:184::o;126856:299::-;127065:14;78830:9;78805:22;78799:29;78796:44;78793:161;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41;118092:28:::1;::::0;;;:16:::1;:28;::::0;;;;;126996:10;;118092:28:::1;;118088:57;;;118129:16;;-1:-1:-1::0;;;118129:16:0::1;;;;;;;;;;;118088:57;127028:10:::2;127040:5;117754:15;117746:5;:23;:74;;;-1:-1:-1::0;117781:24:0::2;::::0;;;:12:::2;:24;::::0;;;;:39:::2;;::::0;117773:47;::::2;117746:74;:141;;;-1:-1:-1::0;117850:24:0::2;::::0;;;:12:::2;:24;::::0;;;;:37:::2;;::::0;117841:46;::::2;;117746:141;:170;;;-1:-1:-1::0;117891:20:0::2;117899:12;117891:5:::0;:20:::2;:::i;:::-;:25:::0;::::2;117746:170;117728:224;;;117935:17;;-1:-1:-1::0;;;117935:17:0::2;;;;;;;;;;;117728:224;127106:41:::3;127119:10;127131:5;127138:8;;127106:12;:41::i;:::-;79141:10:::0;79117:22;79110:42;127097:50;126856:299;-1:-1:-1;;;;;;;;126856:299:0:o;141880:1464::-;118092:28;;;;:16;:28;;;;;;141942:10;;118092:28;;118088:57;;;118129:16;;-1:-1:-1;;;118129:16:0;;;;;;;;;;;118088:57;78830:9:::1;78805:22;78799:29;78796:44:::0;78793:161:::1;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41:::0;142038:25:::2;142066:24:::0;;;:12:::2;:24;::::0;;;;142171:21:::2;::::0;::::2;::::0;142066:24;;142123:15:::2;::::0;142171:43:::2;::::0;111450:8:::2;::::0;142171:43:::2;:::i;:::-;142149:65:::0;-1:-1:-1;142225:19:0::2;142247:33;111580:7;142149:65:::0;142247:33:::2;:::i;:::-;142310:16;::::0;::::2;::::0;142407:23:::2;::::0;::::2;::::0;142225:55;;-1:-1:-1;;;;;;142310:16:0::2;::::0;142393:37;::::2;142389:815;;;142495:30;142514:10;142495:18;:30::i;:::-;142540:53;142557:10;142569:8;:23;;;142540:16;:53::i;:::-;142389:815;;;142629:11;142615;:25;142611:593;;;142727:20;;-1:-1:-1::0;;;142727:20:0::2;;;;;;;;;;;142611:593;142783:11;142769;:25;142765:439;;;142875:30;142894:10;142875:18;:30::i;:::-;142920:57;142943:10;142955:8;:21;;;142920:22;:57::i;142765:439::-;143097:57;143120:10;143132:8;:21;;;143097:22;:57::i;:::-;-1:-1:-1::0;143180:12:0::2;::::0;-1:-1:-1;;;;;143180:12:0::2;142765:439;143277:26;::::0;::::2;::::0;143305:20:::2;::::0;::::2;::::0;143250:86:::2;::::0;143265:10;;-1:-1:-1;;;;;143305:20:0::2;143327:8:::0;143250:14:::2;:86::i;:::-;141967:1377;;;;;79141:10:::1;79117:22;79110:42;141880:1464:::0;;:::o;134117:2729::-;134477:18;78830:9;78805:22;78799:29;78796:44;78793:161;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41;134562:15:::1;134544:33;;:15;:33;;;134540:61;;;134586:15;;-1:-1:-1::0;;;134586:15:0::1;;;;;;;;;;;134540:61;134616:22:::0;;;:47:::1;;-1:-1:-1::0;134642:21:0;;134616:47:::1;134612:72;;;134672:12;;-1:-1:-1::0;;;134672:12:0::1;;;;;;;;;;;134612:72;-1:-1:-1::0;;;;;134699:25:0;::::1;::::0;;:48:::1;;-1:-1:-1::0;;;;;;134728:19:0;::::1;::::0;134699:48:::1;134695:75;;;134756:14;;-1:-1:-1::0;;;134756:14:0::1;;;;;;;;;;;134695:75;111708:2;134785:45:::0;::::1;134781:73;;;134839:15;;-1:-1:-1::0;;;134839:15:0::1;;;;;;;;;;;134781:73;134973:24:::0;::::1;134918:12;135022:9:::0;;;135018:37:::1;;135040:15;;-1:-1:-1::0;;;135040:15:0::1;;;;;;;;;;;135018:37;135122:181;135177:11;135209:10;135246:4;135274:17;135122:32;:181::i;:::-;135387:13;::::0;;;-1:-1:-1;135455:13:0::1;135453:15;135387:13:::0;135453:15:::1;:::i;:::-;::::0;;;-1:-1:-1;135481:22:0::1;135523:12;135506:14;:12;:14::i;:::-;:29;;;;:::i;:::-;135481:54;;135605:476;;;;;;;;135638:7;135605:476;;;;135667:5;-1:-1:-1::0;;;;;135605:476:0::1;;;;;135696:7;-1:-1:-1::0;;;;;135605:476:0::1;;;;;135731:11;-1:-1:-1::0;;;;;135605:476:0::1;;;;;135774:15;135605:476;;;;;;135822:16;135605:476;;;;135872:17;135605:476;;;;135922:1;135605:476;;;;135954:14;135605:476;;;;136032:12;136014:15;:30;;;;;;:::i;:::-;135997:47;::::0;:14;:47:::1;:::i;:::-;135605:476:::0;;-1:-1:-1;;;;;135605:476:0;;::::1;;::::0;;::::1;::::0;-1:-1:-1;135578:24:0;;;:12:::1;:24:::0;;;;;;;;:503;;;;;;::::1;::::0;::::1;::::0;;::::1;::::0;;;;::::1;-1:-1:-1::0;;;;;;135578:503:0;;::::1;;::::0;;;;::::1;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;-1:-1:-1::0;;;135578:503:0::1;-1:-1:-1::0;;;;;;135578:503:0;;;;;::::1;::::0;;;;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;;::::1;::::0;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;136223:44:::1;::::0;:17;;135578:503;136223:44;::::1;:24;:44::i;:::-;136158:30;::::0;;;:18:::1;:30;::::0;;;;;;;:46;;;;;;;;:109;;;;136380:33;;;:21:::1;:33:::0;;;;;;136424:157:::1;136444:20:::0;;::::1;136424:157;;;136514:1;136490:9:::0;;136500:1;136490:12;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;136490:26:0::1;136486:40:::0;136518:8:::1;136486:40;136541:28;136556:9;;136566:1;136556:12;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;136541:10:::0;;:14:::1;:28::i;:::-;;136424:157;136466:3:::0;::::1;::::0;::::1;:::i;:::-;;;;136424:157;;;;136675:11;136647:13;:25;136661:10;136647:25;;;;;;;;;;;;:39;;;;;;;;;;;;;;;;;;136704:134;136734:10;136746:5;136753:7;136762:11;136775:15;136792:16;136810:17;136704:134;;;;;;;;;;;13679:25:1::0;;;-1:-1:-1;;;;;13778:15:1;;;13773:2;13758:18;;13751:43;13830:15;;;13825:2;13810:18;;13803:43;13882:15;;;;13877:2;13862:18;;13855:43;13947:4;13935:17;;;;13929:3;13914:19;;13907:46;13731:3;13969:19;;13962:35;;;;14028:3;14013:19;;14006:35;13666:3;13651:19;;13368:679;136704:134:0::1;;;;;;;;134497:2349;;;79141:10:::0;79117:22;79110:42;134117:2729;;;;;;;;;;;;;:::o;149833:203::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;-1:-1:-1;;;;;149927:31:0;::::1;149923:58;;149967:14;;-1:-1:-1::0;;;149967:14:0::1;;;;;;;;;;;149923:58;149992:16;:36:::0;;-1:-1:-1;;;;;;149992:36:0::1;-1:-1:-1::0;;;;;149992:36:0;;;::::1;::::0;;;::::1;::::0;;149833:203::o;148716:183::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;148816:5:::1;148809:4;:12;148805:40;;;148830:15;;-1:-1:-1::0;;;148830:15:0::1;;;;;;;;;;;148805:40;-1:-1:-1::0;;;;;148856:28:0;;::::1;;::::0;;;:18:::1;:28;::::0;;;;:35;148716:183::o;148104:236::-;117023:10;;-1:-1:-1;;;;;117023:10:0;117009;:24;117005:59;;117042:22;;-1:-1:-1;;;117042:22:0;;;;;;;;;;;117005:59;-1:-1:-1;;;;;148217:21:0;::::1;148213:48;;148247:14;;-1:-1:-1::0;;;148247:14:0::1;;;;;;;;;;;148213:48;148316:6;:16:::0;;-1:-1:-1;;;;;;148316:16:0::1;-1:-1:-1::0;;;;;148316:16:0;;;::::1;::::0;;;::::1;::::0;;148104:236::o;139781:1997::-;78830:9;78805:22;78799:29;78796:44;78793:161;;78873:10;78867:4;78860:24;78934:4;78928;78921:18;78793:161;78999:9;78975:22;78968:41;118092:28:::1;::::0;;;:16:::1;:28;::::0;;;;;139922:10;;118092:28:::1;;118088:57;;;118129:16;;-1:-1:-1::0;;;118129:16:0::1;;;;;;;;;;;118088:57;139950:13:::2;139966:14;:12;:14::i;:::-;139950:30;;140067:17;140088:1;140067:22:::0;140063:47:::2;;140098:12;;-1:-1:-1::0;;;140098:12:0::2;;;;;;;;;;;140063:47;140167:1;140125:38;140145:10;140157:5;140125:19;:38::i;:::-;:43;140121:72;;140177:16;;-1:-1:-1::0;;;140177:16:0::2;;;;;;;;;;;140121:72;140290:38;140331:31:::0;;;:19:::2;:31;::::0;;;;;;;:38;;;;;;;;;140290:79;;::::2;::::0;::::2;::::0;;;;::::2;;::::0;;;;::::2;::::0;;;::::2;::::0;;;::::2;::::0;::::2;::::0;;;;;;;;::::2;;::::0;;;;;140384:38;;::::2;::::0;:88:::2;;-1:-1:-1::0;140427:30:0::2;::::0;;;:18:::2;:30;::::0;;;;;;;:37;;;;;;;;:45:::2;;::::0;::::2;;140426:46;140384:88;140380:143;;;140496:15;;-1:-1:-1::0;;;140496:15:0::2;;;;;;;;;;;140380:143;140575:21;140584:12;140575:21:::0;::::2;:::i;:::-;140641:25;140669:24:::0;;;:12:::2;:24;::::0;;;;;;;140784:19:::2;:31:::0;;;;;:38;;;;;;;;;140766:56;;::::2;::::0;::::2;::::0;;;;::::2;;::::0;;;;::::2;::::0;;;::::2;::::0;;;;::::2;::::0;::::2;::::0;;;;;;;;::::2;::::0;;::::2;::::0;;;;;140939:20;::::2;::::0;140575:21;;-1:-1:-1;140766:56:0;-1:-1:-1;140669:24:0;140884:190:::2;::::0;-1:-1:-1;;;;;140939:20:0::2;140980:10;141017:4;141045:17:::0;140884:32:::2;:190::i;:::-;141130:33;::::0;::::2;::::0;:38;141126:468:::2;;141222:17;141185:15;:33;;:54;;;;;;;:::i;:::-;::::0;;-1:-1:-1;141126:468:0::2;;;141290:292;::::0;;::::2;::::0;::::2;::::0;;;141342:24:::2;::::0;::::2;::::0;-1:-1:-1;;;141342:24:0;::::2;;;141290:292:::0;;141404:26:::2;::::0;::::2;::::0;141290:292:::2;::::0;::::2;::::0;141404:46:::2;::::0;141433:17;;141404:46:::2;:::i;:::-;141290:292;;;;141487:8;:25;;;141290:292;;;;141545:8;:21;;;141290:292;;::::0;141272:310:::2;;141126:468;141656:31;::::0;;;:19:::2;:31;::::0;;;;;;;:38;;;;;;;;;:56;;;;-1:-1:-1;;141656:56:0::2;;::::0;;::::2;;::::0;;;;::::2;::::0;-1:-1:-1;141656:56:0;::::2;::::0;;;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;::::0;141730:40;;12510:25:1;;;12551:18;;;12544:34;;;141730:40:0::2;::::0;12483:18:1;141730:40:0::2;;;;;;;139939:1839;;;79030:1:::1;79141:10:::0;79117:22;79110:42;139781:1997;;:::o;121797:1340::-;121898:15;;122060;118092:28;;;:16;:28;;;;;;122060:15;;121898;118092:28;;118088:57;;;118129:16;;-1:-1:-1;;;118129:16:0;;;;;;;;;;;118088:57;121935:15;;121952:10:::1;::::0;::::1;::::0;117754:15:::1;117746:23:::0;::::1;::::0;:74:::1;;-1:-1:-1::0;117781:24:0::1;::::0;;;:12:::1;:24;::::0;;;;:39:::1;;::::0;117773:47;::::1;117746:74;:141;;;-1:-1:-1::0;117850:24:0::1;::::0;;;:12:::1;:24;::::0;;;;:37:::1;;::::0;117841:46;::::1;;117746:141;:170;;;-1:-1:-1::0;117891:20:0::1;117899:12;117891:5:::0;:20:::1;:::i;:::-;:25:::0;::::1;117746:170;117728:224;;;117935:17;;-1:-1:-1::0;;;117935:17:0::1;;;;;;;;;;;117728:224;121999:15:::0;;122016:12:::2;::::0;;::::2;::::0;122030:10:::2;::::0;::::2;::::0;121999:15:::2;117290:33:::0;;;:21:::2;:33:::0;;;;;;122016:12;;122030:10;;117290:51:::2;::::0;122016:12;117290:42:::2;:51::i;:::-;117356:25;::::0;;;:13:::2;:25;::::0;;;;;117274:67;;-1:-1:-1;117356:25:0::2;;:38:::0;::::2;;;;117386:8;117385:9;117356:38;117352:201;;;117418:21;;-1:-1:-1::0;;;117418:21:0::2;;;;;;;;;;;117352:201;117462:25;::::0;;;:13:::2;:25;::::0;;;;;::::2;;117461:26;:38:::0;::::2;;;;117491:8;117461:38;117457:96;;;117523:18;;-1:-1:-1::0;;;117523:18:0::2;;;;;;;;;;;117457:96;122147:51:::3;122160:4;:15;;;122177:4;:10;;;122189:8;;122147:12;:51::i;:::-;122134:10;::::0;::::3;:64:::0;122283:15:::3;122134:4:::0;122283:9:::3;:15::i;:::-;122278:30;;122307:1;122300:8;;;;122278:30;122417:27;122439:4;122417:21;:27::i;:::-;122379:4;:18;;122399:4;:14;;122378:66;;;::::0;::::3;;;::::0;::::3;;122678:12;:29;122691:4;:15;;;122678:29;;;;;;;;;;;:47;;;122644:4;:14;;;122623:4;:18;;;122579:24;:41;122604:4;:15;;;122579:41;;;;;;;;;;;;:62;;;;:::i;:::-;:79;;;;:::i;:::-;:146;122561:219;;;122744:36;;-1:-1:-1::0;;;122744:36:0::3;;;;;;;;;;;122561:219;122882:23;122900:4;122882:17;:23::i;:::-;122968:21;122984:4;122968:15;:21::i;:::-;123030:4;:12;;;-1:-1:-1::0;;;;;123007:84:0::3;123013:4;:15;;;123007:84;123044:4;:18;;;123064:4;:14;;;123080:4;:10;;;123007:84;;;;;;;14254:25:1::0;;;14310:2;14295:18;;14288:34;;;;14353:2;14338:18;;14331:34;14242:2;14227:18;;14052:319;123007:84:0::3;;;;;;;;123111:4;:18;;;123104:25;;117563:1;117263:309:::2;117963:1;;;118156::::1;;121797:1340:::0;;;;;;:::o;118512:183::-;118603:24;;;;:12;:24;;;;;:32;;;-1:-1:-1;;;;;118603:32:0;118589:10;:46;;;;:70;;-1:-1:-1;118653:6:0;;-1:-1:-1;;;;;118653:6:0;118639:10;:20;;118589:70;118585:102;;;118668:19;;-1:-1:-1;;;118668:19:0;;;;;;;;;;;118585:102;118512:183;:::o;88856:1160::-;89042:4;89036:11;89108:6;89102:4;89095:20;89174:2;89168:4;89161:16;89240:4;89236:2;89232:13;89226:4;89219:27;-1:-1:-1;;;89297:4:0;89290:48;89709:4;89703;89697;89691;89688:1;89681:5;89674;89669:45;89602:16;89595:24;89591:1;89584:4;89578:11;89575:18;89572:48;89486:247;89458:412;;89781:10;89775:4;89768:24;89850:4;89844;89837:18;89458:412;89897:1;89891:4;89884:15;89954:4;89947:15;-1:-1:-1;;;;88856:1160:0:o;19064:1562::-;24694:33;24688:4;24681:47;19163:16;24742:20;;;24797:4;24781:21;;19127:23;;19163:33;19285:14;19337:8;19331:15;19387:10;19382:3;19378:20;19373:3;19369:30;19429:4;19423:11;19413:21;;19467:6;19461:4;19457:17;19505:10;19501:2;19497:19;19488:28;;19560:2;19557:1;19554:9;19547:17;19544:1;19540:25;19537:1;19530:36;19621:1;19611:633;;19650:1;19647:551;;;19684:1;19679:6;;19744:1;19734:8;19730:16;19724:23;19720:2;19716:32;19711:37;;19777:1;19774:401;;;19881:9;;;19874:17;19867:25;;;19860:4;19853:12;;19846:47;-1:-1:-1;19815:1:0;19942:16;;;19936:23;19932:2;19928:32;;19990:158;;;;20035:1;20030:6;;20111:2;20108:1;20105:9;20098:17;20095:1;20091:25;20084:4;20081:1;20077:12;20070:47;19990:158;20220:5;;19611:633;20271:1;20267:9;;;;20294:200;20319:1;20316;20313:8;20294:200;;;20383:16;;;20377:23;20373:2;20369:32;20463:9;;;20456:17;20449:25;;20441:1;20437:9;;;20430:17;;20423:52;20369:32;-1:-1:-1;20336:1:0;20329:9;20294:200;;;20298:14;19580:952;20561:1;20553:6;20546:17;20604:1;20601;20597:9;20594:1;20590:17;20584:4;20577:31;;;;;19260:1359;19064:1562;;;:::o;127401:1392::-;127501:7;129530:30;;;:18;:30;;;;;;;;:37;;;;;;;;127642:14;;;;;;127638:32;;;127665:5;127658:12;;;;;127638:32;127730:35;127747:10;127759:5;127730:16;:35::i;:::-;127859:24;;;;:12;:24;;;;;:39;;;:54;;127901:12;;127859:54;:::i;:::-;127850:5;:63;127846:137;;127930:41;127953:10;127965:5;127930:22;:41::i;:::-;128056:24;128083:38;128103:10;128115:5;128083:19;:38::i;:::-;128056:65;;128132:38;128173:33;128195:10;128173:21;:33::i;:::-;128132:74;;128302:1;128283:16;:20;:140;;128393:30;128283:140;;;128319:58;:30;128357:1;128360:16;128319:37;:58::i;:::-;128258:165;;128478:57;128499:10;128511:5;128258:6;128526:8;;128478:20;:57::i;:::-;128670:15;;;;128645:22;;:40;;128670:15;128645:40;:::i;:::-;128599:24;;;;:12;:24;;;;;:41;;:87;;:41;;:24;:87;;;;;:::i;:::-;;;;-1:-1:-1;;;;128741:14:0;;:21;;-1:-1:-1;;128741:21:0;128758:4;128741:21;;;-1:-1:-1;128780:5:0;;127401:1392;-1:-1:-1;;;127401:1392:0:o;144473:827::-;144594:38;144635:31;;;:19;:31;;;;;;;;:38;;;;;;;;;144594:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;144743:38;144739:554;;144834:25;144862:24;;;:12;:24;;;;;;;;;144971:28;;;;144947:21;;;:52;145041:31;;145014:24;;;:58;;;;;;-1:-1:-1;;;145014:58:0;-1:-1:-1;;;;145014:58:0;;;;;;;;;145115:32;;;;145087:25;;;:60;145191:33;;;;-1:-1:-1;145162:26:0;;:62;145246:35;;12510:25:1;;;12551:18;;;12544:34;;;144862:24:0;145246:35;;12483:18:1;145246:35:0;;;;;;;144783:510;144739:554;144543:757;144473:827;;:::o;128954:272::-;129046:29;129078:30;;;:18;:30;;;;;129046:29;129109:20;129117:12;129109:5;:20;:::i;:::-;129078:52;;;;;;;;;;;-1:-1:-1;129078:52:0;129146:22;;;;129078:52;;-1:-1:-1;129146:22:0;;129141:78;;129192:15;;-1:-1:-1;;;129192:15:0;;;;;;;;;;;143629:671;143815:16;143854:36;;;:24;:36;;;;;;143834:56;;:17;:56;:::i;:::-;143815:75;;143960:82;143997:11;144014:8;144032;143960:28;:82::i;:::-;144102:36;;;;:24;:36;;;;;;;;:56;;;144213:16;:28;;;;;;:35;;-1:-1:-1;;144213:35:0;144244:4;144213:35;;;144266:26;;529:25:1;;;144266:26:0;;502:18:1;144266:26:0;;;;;;;143762:538;143629:671;;;;:::o;52675:493::-;52842:9;;;52973;;52987;;;52984:16;;52970:31;52966:39;;52956:166;;53039:10;53033:4;53026:24;53102:4;53096;53089:18;52956:166;53141:9;;52675:493;-1:-1:-1;;52675:493:0:o;8683:2378::-;24694:33;24688:4;24681:47;8753:11;24742:20;;;24797:4;24781:21;;-1:-1:-1;;;;;8898:23:0;;;;;-1:-1:-1;;8938:25:0;;8935:151;;8996:10;8990:4;8983:24;9066:4;9060;9053:18;8935:151;9110:5;9100:44;;9128:14;9119:23;;9100:44;9176:15;;9220:30;;;9290:8;9284:4;9277:22;9327:1;9317:1287;;9371:10;9367:2;9363:19;9414:2;9404:164;;9470:5;9466:2;9462:14;9452:8;9445:32;9513:1;9503:11;;9540:5;;;9404:164;9600:5;9596:2;9593:13;9590:26;;9609:5;;;9590:26;9676:1;9666:8;9662:16;9656:23;9652:2;9648:32;9712:2;9702:172;;9776:5;9772:2;9768:14;9764:1;9754:8;9750:16;9743:40;9819:1;9809:11;;9846:5;;;;9702:172;9906:5;9902:2;9899:13;9896:26;;9915:5;;;;9896:26;9982:1;9972:8;9968:16;9962:23;9958:2;9954:32;10018:2;10008:172;;10082:5;10078:2;10074:14;10070:1;10060:8;10056:16;10049:40;10125:1;10115:11;;10152:5;;;;;10008:172;10212:5;10208:2;10205:13;10202:26;;10221:5;;;;;10202:26;10257:4;10250:16;;;10311:4;10295:21;;;10318:1;10288:32;;10342:16;;;10387:21;;;10410:1;10380:32;;10434:16;;10479:21;;10502:1;10472:32;;-1:-1:-1;10555:1:0;10540:17;;;;9317:1287;10635:5;10629:4;10622:19;10684:4;10678;10668:21;10723:1;10717:8;10707:298;;10762:1;10759;10755:9;10750:14;;10819:5;10815:2;10811:14;10807:1;10797:8;10793:16;10786:40;10865:1;10862;10858:9;10855:1;10848:20;10914:10;10911:1;10907:18;10897:8;10890:36;10958:1;10948:11;;10981:5;;;10707:298;;9205:1838;9209:43;;8874:2180;8683:2378;;;;:::o;5909:1144::-;24694:33;24688:4;24681:47;5989:11;24742:20;;;24797:4;24781:21;;-1:-1:-1;;;;;6134:23:0;;;;;-1:-1:-1;;6174:25:0;;6171:151;;6232:10;6226:4;6219:24;6302:4;6296;6289:18;6171:151;6346:5;6336:44;;6364:14;6355:23;;6336:44;6418:8;6412:15;6482:30;;;6472:376;;6547:1;6537:11;;6597:5;6584:10;6580:2;6576:19;6573:30;6570:43;6606:5;6570:43;6669:1;6655:16;;6649:23;6645:2;6641:32;6635:56;;6684:5;6635:56;6747:1;6733:16;;6727:23;6723:2;6719:32;6713:56;;6762:5;6713:56;6801:1;6791:11;;6824:5;;6472:376;6879:8;6873:4;6866:22;6919:5;6913:4;6906:19;6989:4;6983;6973:21;6967:28;6960:36;6953:44;6943:54;;6441:594;6445:2;6110:936;5909:1144;;;;:::o;123294:959::-;123468:15;;123359:4;123455:29;;;:12;:29;;;;;;;;123615:12;;;;123629:14;;;;123645:10;;;;123583:73;;-1:-1:-1;;;123583:73:0;;-1:-1:-1;;;;;14634:15:1;;;123583:73:0;;;14616:34:1;123629:14:0;;;14666:18:1;;;14659:43;14718:18;;;14711:34;;;;123359:4:0;;123595:6;123583:31;;;;;;14551:18:1;;123583:73:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123557:99;;123728:24;123801:15;111450:8;123755;:21;;;:43;;;;:::i;:::-;123976:15;;123926:25;123954:38;;;:21;:38;;;;;;;;123993:10;;;;123954:50;;;;;;;124005:12;;;;-1:-1:-1;;;;;123954:64:0;;;;;;;;;123755:61;;;;;-1:-1:-1;123926:25:0;123954:69;;:152;;-1:-1:-1;124059:15:0;;124040:35;;;;:18;:35;;;;;;;;124076:10;;;;124040:47;;;;;;;:61;;;:66;123954:152;123926:180;;124180:18;:41;;;;;124202:19;124180:41;:65;;;;;124225:20;124180:65;124173:72;123294:959;-1:-1:-1;;;;;;123294:959:0:o;124458:1062::-;124712:15;;124562:21;124699:29;;;:12;:29;;;;;;;;124855:12;;;;124869:14;;;;124885:10;;;;124819:77;;-1:-1:-1;;;124819:77:0;;-1:-1:-1;;;;;14634:15:1;;;124819:77:0;;;14616:34:1;124869:14:0;;;14666:18:1;;;14659:43;14718:18;;;14711:34;;;;124562:21:0;;124699:29;124562:21;;124831:6;124819:35;;;;14551:18:1;;124819:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125062:15;;125043:35;;;;:18;:35;;;;;;;;125079:10;;;;125043:47;;;;;;;:61;;;124797:99;;-1:-1:-1;125024:87:0;;124797:99;;125106:4;125024:18;:87::i;:::-;125249:16;;;;-1:-1:-1;;;;;125249:16:0;125213:14;125230:36;;;:18;:36;;;;;;125008:103;;-1:-1:-1;125213:14:0;125230:85;;125312:3;;125230:85;;;125292:16;;;;-1:-1:-1;;;;;125292:16:0;125273:36;;;;:18;:36;;;;;;125230:85;125213:102;-1:-1:-1;125381:34:0;:13;125213:102;125410:4;125381:20;:34::i;:::-;125369:46;-1:-1:-1;125486:26:0;125369:46;125486:26;;:::i;:::-;;;124609:911;;;124458:1062;;;:::o;125607:429::-;125856:4;:14;;;125835:4;:18;;;:35;;;;:::i;:::-;125790:15;;125768:38;;;;:21;:38;;;;;;;;125807:10;;;;125768:50;;;;;;;125819:12;;;;-1:-1:-1;;;;;125768:64:0;;;;;;;;:102;126014:14;;;;125993:18;;;;:35;;126014:14;125993:35;:::i;:::-;125973:15;;125948:41;;;;:24;:41;;;;;:80;;:41;;;:80;;;;;:::i;:::-;;;;-1:-1:-1;;;125607:429:0:o;126128:480::-;126285:15;;126250:19;126272:29;;;:12;:29;;;;;;;:41;;;126428:13;;;;126443:18;;;;-1:-1:-1;;;;;126272:41:0;;;;126386:76;;126272:41;;126386:28;:76::i;:::-;126571:12;;126585:14;;;;126529:71;;126558:11;;-1:-1:-1;;;;;126571:12:0;;;;126529:28;:71::i;:::-;126185:423;126128:480;:::o;129771:243::-;129845:19;129936:24;;;:12;:24;;;;;:41;;;;129891:42;;;;;:86;;129936:41;129891:86;:::i;130267:2040::-;130454:18;130475:35;130492:10;130504:5;130475:16;:35::i;:::-;130454:56;;130596:10;130610:1;130596:15;130592:109;;-1:-1:-1;130646:22:0;;130628:15;;;:40;130683:7;;130592:109;130713:25;130741:24;;;:12;:24;;;;;130843:22;;130741:24;;130713:25;130843:47;;130873:4;130879:10;130843:29;:47::i;:::-;130819:71;;130981:8;:25;;;130965:13;:41;130961:1238;;;-1:-1:-1;131039:25:0;;;;131127:16;131171:38;131039:25;131192:10;131204:4;131171:20;:38::i;:::-;131146:22;;:63;;;;:::i;:::-;131284:13;;;;131127:82;;-1:-1:-1;;;;;;131284:13:0;131316:18;;131312:876;;131447:20;;;;131410:87;;-1:-1:-1;;;;;131447:20:0;131473:4;131487:8;131410:28;:87::i;:::-;131553:4;-1:-1:-1;;;;;131553:9:0;131634:26;;;131687:10;131724:8;:16;;;131767:8;:20;;;;;;;;;;-1:-1:-1;;;;;131767:20:0;131814:5;131846:8;131881;;131585:327;;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;131585:327:0;;;;;;;;;;;;;;-1:-1:-1;;;;;131585:327:0;-1:-1:-1;;;;;;131585:327:0;;;;;;;;;;131553:378;;;;131585:327;131553:378;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;132006:36:0;;;;:24;:36;;;;;:48;;132046:8;;132006:36;:48;;132046:8;;132006:48;:::i;:::-;;;;-1:-1:-1;131312:876:0;;-1:-1:-1;131312:876:0;;132164:8;132145:6;:15;;;:27;;;;;;;:::i;:::-;;;;-1:-1:-1;;131312:876:0;131008:1191;;130961:1238;132263:20;;;:36;-1:-1:-1;;130267:2040:0;;;;;;:::o;93303:957::-;93469:2;93463:4;93456:16;93527:6;93521:4;93514:20;-1:-1:-1;;;93587:4:0;93580:48;93987:4;93981;93975;93969;93966:1;93959:5;93952;93947:45;93880:16;93873:24;93869:1;93862:4;93856:11;93853:18;93850:48;93764:247;93736:408;;94059:10;94053:4;94046:24;94124:4;94118;94111:18;93736:408;94171:1;94165:4;94158:15;93303:957;;;:::o;132519:904::-;132603:7;132729:33;;;:21;:33;;;;;;;;132881:12;:24;;;;;;:30;;;132847:72;;-1:-1:-1;;;132847:72:0;;-1:-1:-1;;;;;132881:30:0;;;132847:72;;;16567:51:1;16634:18;;;16627:34;;;132603:7:0;;132859:6;132847:33;;;;16540:18:1;;132847:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132826:93;-1:-1:-1;132987:22:0;;133020:210;133044:22;:13;:20;:22::i;:::-;133040:1;:26;133020:210;;;-1:-1:-1;;;;;133135:6:0;133123:35;;133159:19;:13;133176:1;133159:16;:19::i;:::-;133180:24;;;;:12;:24;;;;;;;:30;;;133123:95;;;;;;-1:-1:-1;;;;;;133123:95:0;;;-1:-1:-1;;;;;14634:15:1;;;133123:95:0;;;14616:34:1;133180:30:0;;14666:18:1;;;14659:43;14718:18;;;14711:34;;;14551:18;;133123:95:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;133088:130;;;;:::i;:::-;;-1:-1:-1;133068:3:0;;;;:::i;:::-;;;;133020:210;;;-1:-1:-1;133246:25:0;;;;:13;:25;;;;;;;;133242:79;;;133295:14;-1:-1:-1;133288:21:0;;-1:-1:-1;;133288:21:0;133242:79;133388:27;133401:14;133388:10;:27;:::i;4050:666::-;24694:33;24688:4;24681:47;4113:14;24742:20;;;24797:4;24781:21;;4276:8;4270:15;4326:10;4321:3;4317:20;4312:3;4308:30;4369:1;4366;4362:9;4352:19;;4431:1;4417:10;4413:2;4409:19;4402:27;4399:34;4385:313;;4467:1;4457:11;;4516:6;4506:8;4502:21;4496:28;4486:49;4528:5;4486:49;4563:1;4553:11;;4612:6;4602:8;4598:21;4592:28;4582:49;4624:5;4582:49;4659:1;4649:11;;4385:313;4389:2;;4237:472;4050:666;;;:::o;22918:398::-;24694:33;24688:4;24681:47;22988:14;24742:20;;;24797:4;24781:21;;23165:1;23155:8;23151:16;23145:23;23141:2;23137:32;23127:42;;23223:14;23215:6;23212:26;23205:34;23197:6;23193:47;23183:57;;23270:11;23277:3;23270:6;:11::i;:::-;23265:1;:16;23261:47;;23290:18;;-1:-1:-1;;;23290:18:0;;;;;;;;;;;23261:47;23004:312;22918:398;;;;:::o;14:173:1:-;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:70;;177:1;174;167:12;111:70;14:173;;;:::o;192:186::-;251:6;304:2;292:9;283:7;279:23;275:32;272:52;;;320:1;317;310:12;272:52;343:29;362:9;343:29;:::i;:::-;333:39;192:186;-1:-1:-1;;;192:186:1:o;565:347::-;616:8;626:6;680:3;673:4;665:6;661:17;657:27;647:55;;698:1;695;688:12;647:55;-1:-1:-1;721:20:1;;764:18;753:30;;750:50;;;796:1;793;786:12;750:50;833:4;825:6;821:17;809:29;;885:3;878:4;869:6;861;857:19;853:30;850:39;847:59;;;902:1;899;892:12;847:59;565:347;;;;;:::o;917:620::-;1014:6;1022;1030;1038;1046;1099:3;1087:9;1078:7;1074:23;1070:33;1067:53;;;1116:1;1113;1106:12;1067:53;1152:9;1139:23;1129:33;;1209:2;1198:9;1194:18;1181:32;1171:42;;1264:2;1253:9;1249:18;1236:32;1291:18;1283:6;1280:30;1277:50;;;1323:1;1320;1313:12;1277:50;1362:58;1412:7;1403:6;1392:9;1388:22;1362:58;:::i;:::-;1439:8;;-1:-1:-1;1336:84:1;-1:-1:-1;1493:38:1;;-1:-1:-1;1527:2:1;1512:18;;1493:38;:::i;:::-;1483:48;;917:620;;;;;;;;:::o;1542:248::-;1610:6;1618;1671:2;1659:9;1650:7;1646:23;1642:32;1639:52;;;1687:1;1684;1677:12;1639:52;-1:-1:-1;;1710:23:1;;;1780:2;1765:18;;;1752:32;;-1:-1:-1;1542:248:1:o;2331:118::-;2417:5;2410:13;2403:21;2396:5;2393:32;2383:60;;2439:1;2436;2429:12;2454:128;2519:20;;2548:28;2519:20;2548:28;:::i;2587:315::-;2652:6;2660;2713:2;2701:9;2692:7;2688:23;2684:32;2681:52;;;2729:1;2726;2719:12;2681:52;2752:29;2771:9;2752:29;:::i;:::-;2742:39;;2831:2;2820:9;2816:18;2803:32;2844:28;2866:5;2844:28;:::i;:::-;2891:5;2881:15;;;2587:315;;;;;:::o;4070:180::-;4129:6;4182:2;4170:9;4161:7;4157:23;4153:32;4150:52;;;4198:1;4195;4188:12;4150:52;-1:-1:-1;4221:23:1;;4070:180;-1:-1:-1;4070:180:1:o;4255:1209::-;4472:13;;4454:32;;4533:4;4521:17;;;4515:24;4441:3;4426:19;;;4548:54;;4581:20;;4515:24;-1:-1:-1;;;;;2973:31:1;2961:44;;2907:104;4548:54;;4651:4;4643:6;4639:17;4633:24;4666:56;4716:4;4705:9;4701:20;4685:14;-1:-1:-1;;;;;2973:31:1;2961:44;;2907:104;4666:56;;4771:4;4763:6;4759:17;4753:24;4786:56;4836:4;4825:9;4821:20;4805:14;-1:-1:-1;;;;;2973:31:1;2961:44;;2907:104;4786:56;;4891:4;4883:6;4879:17;4873:24;4906:54;4954:4;4943:9;4939:20;4923:14;1862:4;1851:16;1839:29;;1795:75;4906:54;;5016:4;5008:6;5004:17;4998:24;4991:4;4980:9;4976:20;4969:54;5079:4;5071:6;5067:17;5061:24;5054:4;5043:9;5039:20;5032:54;5142:4;5134:6;5130:17;5124:24;5117:4;5106:9;5102:20;5095:54;5168:6;5228:2;5220:6;5216:15;5210:22;5205:2;5194:9;5190:18;5183:50;;5252:6;5312:2;5304:6;5300:15;5294:22;5289:2;5278:9;5274:18;5267:50;;5336:6;5391:2;5383:6;5379:15;5373:22;5404:54;5454:2;5443:9;5439:18;5423:14;-1:-1:-1;;;;;2973:31:1;2961:44;;2907:104;5661:322;5738:6;5746;5754;5807:2;5795:9;5786:7;5782:23;5778:32;5775:52;;;5823:1;5820;5813:12;5775:52;5859:9;5846:23;5836:33;;5916:2;5905:9;5901:18;5888:32;5878:42;;5939:38;5973:2;5962:9;5958:18;5939:38;:::i;:::-;5929:48;;5661:322;;;;;:::o;5988:156::-;6054:20;;6114:4;6103:16;;6093:27;;6083:55;;6134:1;6131;6124:12;6149:387;6233:6;6241;6249;6257;6310:3;6298:9;6289:7;6285:23;6281:33;6278:53;;;6327:1;6324;6317:12;6278:53;6363:9;6350:23;6340:33;;6392:36;6424:2;6413:9;6409:18;6392:36;:::i;:::-;6149:387;;6382:46;;-1:-1:-1;;;;6475:2:1;6460:18;;6447:32;;6526:2;6511:18;6498:32;;6149:387::o;6541:658::-;6712:2;6764:21;;;6834:13;;6737:18;;;6856:22;;;6683:4;;6712:2;6935:15;;;;6909:2;6894:18;;;6683:4;6978:195;6992:6;6989:1;6986:13;6978:195;;;7057:13;;-1:-1:-1;;;;;7053:39:1;7041:52;;7148:15;;;;7113:12;;;;7089:1;7007:9;6978:195;;;-1:-1:-1;7190:3:1;;6541:658;-1:-1:-1;;;;;;6541:658:1:o;7204:260::-;7272:6;7280;7333:2;7321:9;7312:7;7308:23;7304:32;7301:52;;;7349:1;7346;7339:12;7301:52;7372:29;7391:9;7372:29;:::i;:::-;7362:39;;7420:38;7454:2;7443:9;7439:18;7420:38;:::i;:::-;7410:48;;7204:260;;;;;:::o;8641:620::-;8738:6;8746;8754;8762;8770;8823:3;8811:9;8802:7;8798:23;8794:33;8791:53;;;8840:1;8837;8830:12;8791:53;8876:9;8863:23;8853:33;;8905:38;8939:2;8928:9;8924:18;8905:38;:::i;:::-;8895:48;;8990:2;8979:9;8975:18;8962:32;8952:42;;9045:2;9034:9;9030:18;9017:32;9072:18;9064:6;9061:30;9058:50;;;9104:1;9101;9094:12;9058:50;9143:58;9193:7;9184:6;9173:9;9169:22;9143:58;:::i;:::-;8641:620;;;;-1:-1:-1;8641:620:1;;-1:-1:-1;9220:8:1;;9117:84;8641:620;-1:-1:-1;;;8641:620:1:o;9672:545::-;9760:6;9768;9776;9784;9837:2;9825:9;9816:7;9812:23;9808:32;9805:52;;;9853:1;9850;9843:12;9805:52;9889:9;9876:23;9866:33;;9946:2;9935:9;9931:18;9918:32;9908:42;;10001:2;9990:9;9986:18;9973:32;10028:18;10020:6;10017:30;10014:50;;;10060:1;10057;10050:12;10014:50;10099:58;10149:7;10140:6;10129:9;10125:22;10099:58;:::i;:::-;9672:545;;;;-1:-1:-1;10176:8:1;-1:-1:-1;;;;9672:545:1:o;10222:1262::-;10384:6;10392;10400;10408;10416;10424;10432;10440;10448;10456;10464:7;10518:3;10506:9;10497:7;10493:23;10489:33;10486:53;;;10535:1;10532;10525:12;10486:53;10571:9;10558:23;10548:33;;10600:38;10634:2;10623:9;10619:18;10600:38;:::i;:::-;10590:48;;10657:38;10691:2;10680:9;10676:18;10657:38;:::i;:::-;10647:48;;10714:38;10748:2;10737:9;10733:18;10714:38;:::i;:::-;10704:48;;10771:37;10803:3;10792:9;10788:19;10771:37;:::i;:::-;10761:47;;10855:3;10844:9;10840:19;10827:33;10817:43;;10907:3;10896:9;10892:19;10879:33;10869:43;;10963:3;10952:9;10948:19;10935:33;10987:18;11028:2;11020:6;11017:14;11014:34;;;11044:1;11041;11034:12;11014:34;11082:6;11071:9;11067:22;11057:32;;11127:7;11120:4;11116:2;11112:13;11108:27;11098:55;;11149:1;11146;11139:12;11098:55;11189:2;11176:16;11215:2;11207:6;11204:14;11201:34;;;11231:1;11228;11221:12;11201:34;11284:7;11279:2;11269:6;11266:1;11262:14;11258:2;11254:23;11250:32;11247:45;11244:65;;;11305:1;11302;11295:12;11244:65;11336:2;11332;11328:11;11318:21;;11358:6;11348:16;;;;;11383:39;11417:3;11406:9;11402:19;11383:39;:::i;:::-;11373:49;;11442:36;11473:3;11462:9;11458:19;11442:36;:::i;:::-;11431:47;;10222:1262;;;;;;;;;;;;;;:::o;11489:254::-;11557:6;11565;11618:2;11606:9;11597:7;11593:23;11589:32;11586:52;;;11634:1;11631;11624:12;11586:52;11657:29;11676:9;11657:29;:::i;:::-;11647:39;11733:2;11718:18;;;;11705:32;;-1:-1:-1;;;11489:254:1:o;11748:127::-;11809:10;11804:3;11800:20;11797:1;11790:31;11840:4;11837:1;11830:15;11864:4;11861:1;11854:15;11880:125;11945:9;;;11966:10;;;11963:36;;;11979:18;;:::i;12010:148::-;12098:4;12077:12;;;12091;;;12073:31;;12116:13;;12113:39;;;12132:18;;:::i;12163:168::-;12236:9;;;12267;;12284:15;;;12278:22;;12264:37;12254:71;;12305:18;;:::i;12589:127::-;12650:10;12645:3;12641:20;12638:1;12631:31;12681:4;12678:1;12671:15;12705:4;12702:1;12695:15;12721:120;12761:1;12787;12777:35;;12792:18;;:::i;:::-;-1:-1:-1;12826:9:1;;12721:120::o;12846:128::-;12913:9;;;12934:11;;;12931:37;;;12948:18;;:::i;12979:112::-;13011:1;13037;13027:35;;13042:18;;:::i;:::-;-1:-1:-1;13076:9:1;;12979:112::o;13096:135::-;13135:3;13156:17;;;13153:43;;13176:18;;:::i;:::-;-1:-1:-1;13223:1:1;13212:13;;13096:135::o;13236:127::-;13297:10;13292:3;13288:20;13285:1;13278:31;13328:4;13325:1;13318:15;13352:4;13349:1;13342:15;14756:245;14823:6;14876:2;14864:9;14855:7;14851:23;14847:32;14844:52;;;14892:1;14889;14882:12;14844:52;14924:9;14918:16;14943:28;14965:5;14943:28;:::i;15006:184::-;15076:6;15129:2;15117:9;15108:7;15104:23;15100:32;15097:52;;;15145:1;15142;15135:12;15097:52;-1:-1:-1;15168:16:1;;15006:184;-1:-1:-1;15006:184:1:o;15195:776::-;15492:6;15481:9;15474:25;15535:6;15530:2;15519:9;15515:18;15508:34;15607:1;15603;15598:3;15594:11;15590:19;15582:6;15578:32;15573:2;15562:9;15558:18;15551:60;15647:6;15642:2;15631:9;15627:18;15620:34;15691:6;15685:3;15674:9;15670:19;15663:35;15735:3;15729;15718:9;15714:19;15707:32;15776:6;15770:3;15759:9;15755:19;15748:35;15834:6;15826;15820:3;15809:9;15805:19;15792:49;15891:1;15861:22;;;15885:3;15857:32;;;15850:43;;;;15954:2;15933:15;;;-1:-1:-1;;15929:29:1;15914:45;15910:55;;15195:776;-1:-1:-1;;;;;;15195:776:1:o;15976:412::-;16105:3;16143:6;16137:13;16168:1;16178:129;16192:6;16189:1;16186:13;16178:129;;;16290:4;16274:14;;;16270:25;;16264:32;16251:11;;;16244:53;16207:12;16178:129;;;-1:-1:-1;16362:1:1;16326:16;;16351:13;;;-1:-1:-1;16326:16:1;15976:412;-1:-1:-1;15976:412:1:o

Swarm Source

ipfs://821177e9e0558a64b619a937b584174ae65a826872de00f2c0df7e654fdc832f

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.