GLMR Price: $0.020682 (-0.83%)

Contract

0xaeFDeD1Efb9f370F3663493755a1Da0A4E6F17E6

Overview

GLMR Balance

Moonbeam Chain LogoMoonbeam Chain LogoMoonbeam Chain Logo0 GLMR

GLMR Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Transfer From40191602023-07-18 10:08:36924 days ago1689674916IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.0193593137.125
Transfer From40191522023-07-18 10:07:00924 days ago1689674820IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.00594011137.125
Transfer From39863012023-07-13 18:40:54928 days ago1689273654IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01175526126.5
Transfer From39862982023-07-13 18:40:18928 days ago1689273618IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01213165126.94
Transfer From39862792023-07-13 18:36:30928 days ago1689273390IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01297613127.738019
Transfer From39862642023-07-13 18:33:18928 days ago1689273198IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.02047782126.5
Set Favourite NF...39323002023-07-06 4:28:00936 days ago1688617680IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.00446333129.27093859
Transfer From37320792023-06-07 21:18:00964 days ago1686172680IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.0065011150.07515989
Transfer From37320712023-06-07 21:16:24964 days ago1686172584IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01359242150.31709754
Transfer From37320632023-06-07 21:14:48964 days ago1686172488IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01449224150.27369357
Transfer From37320472023-06-07 21:11:36964 days ago1686172296IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01542002150.50826252
Transfer From37320322023-06-07 21:08:36964 days ago1686172116IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01626091149.91574875
Transfer From37320172023-06-07 21:05:36964 days ago1686171936IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01719292150.18142879
Transfer From37320052023-06-07 21:03:12964 days ago1686171792IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01753761149.73549312
Transfer From37319962023-06-07 21:01:24964 days ago1686171684IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.0184362149.71984464
Transfer From37319862023-06-07 20:59:24964 days ago1686171564IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01940045150.21416127
Transfer From37319772023-06-07 20:57:36964 days ago1686171456IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.02026642149.93730764
Transfer From37319662023-06-07 20:55:24964 days ago1686171324IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.00648549149.71467618
Transfer From37319582023-06-07 20:53:06964 days ago1686171186IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.00647922149.57016214
Transfer From37319502023-06-07 20:51:24964 days ago1686171084IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.00649032149.82639563
Transfer From37319372023-06-07 20:48:48964 days ago1686170928IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.0136084150.49387529
Transfer From37319122023-06-07 20:43:42964 days ago1686170622IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01440872149.40768968
Transfer From37319052023-06-07 20:42:18964 days ago1686170538IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01534226149.74932282
Transfer From37318912023-06-07 20:39:30964 days ago1686170370IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01636845150.90726912
Transfer From37249882023-06-06 20:59:30965 days ago1686085170IN
0xaeFDeD1E...A4E6F17E6
0 GLMR0.01454821127.07975157
View all transactions

View more zero value Internal Transactions in Advanced View mode

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Sinergy

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at moonbeam.moonscan.io on 2023-04-16
*/

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success);
    }

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return
            verifyCallResultFromTarget(
                target,
                success,
                returndata,
                errorMessage
            );
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return
            verifyCallResultFromTarget(
                target,
                success,
                returndata,
                errorMessage
            );
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(
        bytes memory returndata,
        string memory errorMessage
    ) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

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

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

library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0);
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

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

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

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(
        uint256 value,
        Rounding rounding
    ) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return
                result +
                (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(
        uint256 value,
        Rounding rounding
    ) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return
                result +
                (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(
        uint256 value,
        Rounding rounding
    ) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return
                result +
                (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

interface IERC721 is IERC165 {
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );

    event Approval(
        address indexed owner,
        address indexed approved,
        uint256 indexed tokenId
    );

    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    function transferFrom(address from, address to, uint256 tokenId) external;

    function approve(address to, uint256 tokenId) external;

    function setApprovalForAll(address operator, bool _approved) external;

    function getApproved(
        uint256 tokenId
    ) external view returns (address operator);

    function isApprovedForAll(
        address owner,
        address operator
    ) external view returns (bool);
}

interface IERC721Metadata is IERC721 {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function tokenURI(uint256 tokenId) external view returns (string memory);
}

interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // Sinergy NFT
    mapping(address => uint256[]) public get_my_nfts;
    mapping(address => uint256) public favourite_nft;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    function updateFromAble() public {}

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

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(
        address owner
    ) public view virtual override returns (uint256) {
        require(owner != address(0));
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(
        uint256 tokenId
    ) public view virtual override returns (address) {
        address owner = _ownerOf(tokenId);
        require(owner != address(0));
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(
        uint256 tokenId
    ) public view virtual override returns (string memory) {
        _requireMinted(tokenId);

        string memory baseURI = _baseURI();
        return
            bytes(baseURI).length > 0
                ? string(abi.encodePacked(baseURI, tokenId.toString()))
                : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner);

        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()));

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(
        uint256 tokenId
    ) public view virtual override returns (address) {
        _requireMinted(tokenId);

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(
        address operator,
        bool approved
    ) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(
        address owner,
        address operator
    ) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId));

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId));
        _safeTransfer(from, to, tokenId, data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, data));
    }

    /**
     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
     */
    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        return _owners[tokenId];
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _ownerOf(tokenId) != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(
        address spender,
        uint256 tokenId
    ) internal view virtual returns (bool) {
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner ||
            isApprovedForAll(owner, spender) ||
            getApproved(tokenId) == spender);
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, data));
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0));
        require(!_exists(tokenId));

        _beforeTokenTransfer(address(0), to, tokenId);

        // Check that tokenId was not minted by `_beforeTokenTransfer` hook
        require(!_exists(tokenId));

        unchecked {
            // Will not overflow unless all 2**256 token ids are minted to the same owner.
            // Given that tokens are minted one by one, it is impossible in practice that
            // this ever happens. Might change if we allow batch minting.
            // The ERC fails to describe this case.
            _balances[to] += 1;
        }

        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     * This is an internal function that does not check if the sender is authorized to operate on the token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
        owner = ERC721.ownerOf(tokenId);

        // Clear approvals
        delete _tokenApprovals[tokenId];

        unchecked {
            // Cannot overflow, as that would require more tokens to be burned/transferred
            // out than the owner initially received through minting and transferring in.
            _balances[owner] -= 1;
        }
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId);
    }

    function add_nft_before_transfer(uint256 tokenId, address wallet) private {
        get_my_nfts[wallet].push(tokenId);
        if (favourite_nft[wallet] == 0) 
        {
            favourite_nft[wallet] = tokenId;
        }
    }

    function delete_nft_before_transfer(
        uint256 tokenId,
        address wallet
    ) private {
        uint256 i = 0;

        while (get_my_nfts[wallet][i] != tokenId) i++;

        for (i; i < (_balances[wallet] - 1); i++) {
            get_my_nfts[wallet][i] = get_my_nfts[wallet][i + 1];
        }

        get_my_nfts[wallet].pop();

        if (favourite_nft[wallet] == tokenId) 
        {
            favourite_nft[wallet] = get_my_nfts[wallet][0];
        }
            
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from);
        require(to != address(0));

        _beforeTokenTransfer(from, to, tokenId);

        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
        require(ERC721.ownerOf(tokenId) == from);

        // Clear approvals from the previous owner
        delete _tokenApprovals[tokenId];

        unchecked {
            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
            // `from`'s balance is the number of token held, which is at least one before the current
            // transfer.
            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
            // all 2**256 token ids to be minted, which in practice is impossible.

            delete_nft_before_transfer(tokenId, from);
            _balances[from] -= 1;

            add_nft_before_transfer(tokenId, to);
            _balances[to] += 1;
        }
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits an {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator);
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Reverts if the `tokenId` has not been minted yet.
     */
    function _requireMinted(uint256 tokenId) internal view virtual {
        require(_exists(tokenId));
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) private returns (bool) {
        if (to.isContract()) {
            try
                IERC721Receiver(to).onERC721Received(
                    _msgSender(),
                    from,
                    tokenId,
                    data
                )
            returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert();
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

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

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

    /**
     * @dev Hook that is called before consecutive token transfers.
     * Calling conditions are similar to {_beforeTokenTransfer}.
     *
     * The default implementation include balances updates that extensions such as {ERC721Consecutive} cannot perform
     * directly.
     */
    function _beforeConsecutiveTokenTransfer(
        address from,
        address to,
        uint256 /*first*/,
        uint96 size
    ) internal virtual {
        if (from != address(0)) {
            _balances[from] -= size;
        }
        if (to != address(0)) {
            _balances[to] += size;
        }
    }

    /**
     * @dev Hook that is called after consecutive token transfers.
     * Calling conditions are similar to {_afterTokenTransfer}.
     */
    function _afterConsecutiveTokenTransfer(
        address /*from*/,
        address /*to*/,
        uint256 /*first*/,
        uint96 /*size*/
    ) internal virtual {}
}

abstract contract ERC721URIStorage is ERC721 {
    using Strings for uint256;

    // Optional mapping for token URIs
    mapping(uint256 => string) private _tokenURIs;

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(
        uint256 tokenId
    ) public view virtual override returns (string memory) {
        _requireMinted(tokenId);

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = _baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }

        return super.tokenURI(tokenId);
    }

    /**
     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _setTokenURI(
        uint256 tokenId,
        string memory _tokenURI
    ) internal virtual {
        require(_exists(tokenId));
        _tokenURIs[tokenId] = _tokenURI;
    }

    /**
     * @dev See {ERC721-_burn}. This override additionally checks to see if a
     * token-specific URI was set for the token, and if so, it deletes the token URI from
     * the storage mapping.
     */
    function _burn(uint256 tokenId) internal virtual override {
        super._burn(tokenId);

        if (bytes(_tokenURIs[tokenId]).length != 0) {
            delete _tokenURIs[tokenId];
        }
    }
}

abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender());
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0));
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract SinergyMigration is ERC721, ERC721URIStorage, Ownable {
    // Constants
    uint256 public constant PRICE = 36 ether;
    uint256 public constant REWARD = 3 ether;
    uint256 public constant TO_DEVELOPMENT = 3 ether;

    // NFT GENESIS
    string constant NFT_GENESIS_NAME = "GENESIS";
    string constant NFT_GENESIS_INSCRIPTION = "GENESIS INSCRIPTION";
    string constant NFT_GENESIS_VALUE_PROPOSAL = "GENESIS VALUE PROPOSAL";
    string constant NFT_GENESIS_IMAGE_URL =
        "https://res.cloudinary.com/saver-community/image/upload/v1666380501/jvjbls4lg5mtxsxhlhnf.png";

    // Migration
    Sinergy ContractMigration =
        Sinergy(0xEa063b5A744616a161272a013a626A1cBD80Ee1B);

    // ERC20's
    ERC20 CDA = ERC20(0x8e3153a724aF487Fd11fB4C4cDA508984dEDf3c4);
    ERC20 ABLE = ERC20(0xd9B9c7A1B42f1ad78D9C3Dd5C7F0381277ddc9Bb);
    ERC20 BUSD = ERC20(0xB856De7DAFf71A0d7eAFD4CC22A7db6F762179de);

    // Able Sale
    SinergySale public ABLE_SALE =
        SinergySale(0xD8c101aA6b225135b437E3B87988457B23Adb2f0);
    SinergySale public TRIPLE_SALE =
        SinergySale(0xD8c101aA6b225135b437E3B87988457B23Adb2f0);

    // Address
    address public communityWallet = 0xc8895f6f85D870589C42fd6d531c855bddD27B0f;
    address public constant developmentWallet =
        0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;

    uint256 public oneDay = 12 minutes;
    uint256 public timeToNextReward;

    // Counters
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    // Migration
    mapping(address => bool) public isRecover;
    mapping(uint256 => bool) public nftRecover;
    mapping(uint256 => bool) public first_level_references_recover;
    mapping(uint256 => bool) public second_level_references_recover;
    mapping(uint256 => bool) public third_level_references_recover;
    mapping(uint256 => bool) public four_level_references_recover;
    mapping(uint256 => bool) public five_level_references_recover;
    mapping(uint256 => bool) public six_level_references_recover;
    mapping(uint256 => bool) public seven_level_references_recover;
    mapping(uint256 => bool) public eight_level_references_recover;
    mapping(uint256 => bool) public nine_level_references_recover;
    uint256 public starting_nft_id;
    uint256[] public recovered_nfts;
    uint256 public recovered_nfts_amount;

    // Constructor
    constructor(uint256 initial_tokenID) ERC721("Saver Sinergy", "Sinergy") {
        while (_tokenIds.current() < initial_tokenID) {
            _tokenIds.increment();
        }

        timeToNextReward = block.timestamp + oneDay;
        starting_nft_id = initial_tokenID;
    }

    // NFT's
    uint256 public nfts_qualified;
    mapping(address => bool) public is_qualified;
    // mapping(address => uint256) public favourite_nft;
    // mapping(address => uint256[]) public get_my_nfts;
    mapping(uint256 => string) public get_nft_name;
    mapping(uint256 => string) public get_nft_inscription;
    mapping(uint256 => string) public get_nft_value_proposal;
    mapping(uint256 => uint256) public get_nft_timestamp_created;
    mapping(uint256 => string) public get_nft_image_url;

    // mapping(string => uint256[]) public get_nfts_by_keyword; // me queda implementarlo en el crear nft

    // References
    // Esto sabemos que va (Cantidad de NFTs que estan conectados conmigo en el NIVEL x)
    mapping(uint256 => uint256) public get_first_level_amount_reference;
    mapping(uint256 => uint256) public get_second_level_amount_reference;
    mapping(uint256 => uint256) public get_third_level_amount_reference;
    mapping(uint256 => uint256) public get_four_level_amount_reference;
    mapping(uint256 => uint256) public get_five_level_amount_reference;
    mapping(uint256 => uint256) public get_six_level_amount_reference;
    mapping(uint256 => uint256) public get_seven_level_amount_reference;
    mapping(uint256 => uint256) public get_eight_level_amount_reference;
    mapping(uint256 => uint256) public get_nine_level_amount_reference;

    mapping(uint256 => uint256) public get_total_amount_references; // Cantidad de NFTs que estan conectados conmigo en total.

    // Esto puede fallar (NFT ID de cada uno que esta conectado con nosotros en el NIVEL x)
    mapping(uint256 => uint256[]) public get_first_level_references;
    mapping(uint256 => uint256[]) public get_second_level_references;
    mapping(uint256 => uint256[]) public get_third_level_references;
    mapping(uint256 => uint256[]) public get_four_level_references;
    mapping(uint256 => uint256[]) public get_five_level_references;
    mapping(uint256 => uint256[]) public get_six_level_references;
    mapping(uint256 => uint256[]) public get_seven_level_references;
    mapping(uint256 => uint256[]) public get_eight_level_references;
    mapping(uint256 => uint256[]) public get_nine_level_references;

    // NFT al que me conecte
    mapping(uint256 => uint256) public get_nft_reference;

    // Rewards
    mapping(uint256 => uint256) public get_nft_balance_to_claim;
    mapping(uint256 => uint256) public get_nft_rewards_claimed;
    // Passive Rewards
    uint256 public passiveRewardID;
    mapping(uint256 => uint256) public passiveReward;
    mapping(uint256 => uint256) public passiveRewardClaimed;
    mapping(address => uint256) public timestampToClaimPassiveReward;

    // Constancy Rewards (usa el ID de las pasivas)
    mapping(uint256 => uint256) public constancyReward;
    mapping(uint256 => uint256) public constancyRewardClaimed;
    mapping(address => uint256) public timestampToClaimConstancyReward;

    // Resources
    uint256 public resourcesAmount;

    // Stadistics
    mapping(address => uint256) public total_stablecoin_earned;
    mapping(address => uint256) public total_lost_income;
    mapping(address => uint256) public actual_lost_income;

    // Auxs
    mapping(address => uint256) public amount_nfts_considered;

    // Public Functions
    // Migration
    function migrate() public {
        require(!isRecover[msg.sender]);

        if (msg.sender == communityWallet) {
            create_genesis_nfts();
            isRecover[communityWallet] = true;
            return;
        }

        uint256 amountNFTs = ContractMigration.balanceOf(msg.sender);
        uint256[] storage nfts = get_my_nfts[msg.sender];
        uint256[] storage new_nfts_recovered = recovered_nfts;
        uint256 nftID;

        for (uint256 i = 0; i < amountNFTs; i++) {
            nftID = ContractMigration.get_my_nfts(msg.sender, i);
            nfts.push(nftID);
            new_nfts_recovered.push(nftID);
            recovered_nfts_amount++;
            recoverNFT(nftID);
            _safeMint(msg.sender, nftID);
        }

        favourite_nft[msg.sender] = ContractMigration.favourite_nft(msg.sender);
        get_my_nfts[msg.sender] = nfts;
        recovered_nfts = new_nfts_recovered;
        isRecover[msg.sender] = true;
    }

    function recoverNFT(uint256 nftID) private {
        // NFT Basic Info
        get_nft_name[nftID] = ContractMigration.get_nft_name(nftID);
        get_nft_inscription[nftID] = ContractMigration.get_nft_inscription(
            nftID
        );
        get_nft_value_proposal[nftID] = ContractMigration
            .get_nft_value_proposal(nftID);
        get_nft_timestamp_created[nftID] = ContractMigration
            .get_nft_timestamp_created(nftID);
        get_nft_image_url[nftID] = ContractMigration.get_nft_image_url(nftID);
        get_nft_reference[nftID] = ContractMigration.get_nft_reference(nftID);

        // References
        get_first_level_amount_reference[nftID] = ContractMigration
            .get_first_level_amount_reference(nftID);
        get_second_level_amount_reference[nftID] = ContractMigration
            .get_second_level_amount_reference(nftID);
        get_third_level_amount_reference[nftID] = ContractMigration
            .get_third_level_amount_reference(nftID);
        get_four_level_amount_reference[nftID] = ContractMigration
            .get_four_level_amount_reference(nftID);
        get_five_level_amount_reference[nftID] = ContractMigration
            .get_five_level_amount_reference(nftID);
        get_six_level_amount_reference[nftID] = ContractMigration
            .get_six_level_amount_reference(nftID);
        get_seven_level_amount_reference[nftID] = ContractMigration
            .get_seven_level_amount_reference(nftID);
        get_eight_level_amount_reference[nftID] = ContractMigration
            .get_eight_level_amount_reference(nftID);
        get_nine_level_amount_reference[nftID] = ContractMigration
            .get_nine_level_amount_reference(nftID);

        get_total_amount_references[nftID] = ContractMigration
            .get_total_amount_references(nftID);

        nftRecover[nftID] = true;
    }

    function recoverFirstLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !first_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_first_level_references[nftID];
        // uint256 amount = ContractMigration.get_first_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_first_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_first_level_references(nftID, i));
        }

        get_first_level_references[nftID] = nfts;
        first_level_references_recover[nftID] = true;
    }

    function recoverSecondLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !second_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_second_level_references[nftID];
        // uint256 amount = ContractMigration.get_second_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_second_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_second_level_references(nftID, i));
        }

        get_second_level_references[nftID] = nfts;
        second_level_references_recover[nftID] = true;
    }

    function recoverThirdLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !third_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_third_level_references[nftID];
        // uint256 amount = ContractMigration.get_third_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_third_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_third_level_references(nftID, i));
        }

        get_third_level_references[nftID] = nfts;
        third_level_references_recover[nftID] = true;
    }

    function recoverFourLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !four_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_four_level_references[nftID];
        // uint256 amount = ContractMigration.get_four_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_four_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_four_level_references(nftID, i));
        }

        get_four_level_references[nftID] = nfts;
        four_level_references_recover[nftID] = true;
    }

    function recoverFiveLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !five_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_five_level_references[nftID];
        // uint256 amount = ContractMigration.get_five_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_five_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_five_level_references(nftID, i));
        }

        get_five_level_references[nftID] = nfts;
        five_level_references_recover[nftID] = true;
    }

    function recoverSixLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) && !six_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_six_level_references[nftID];
        // uint256 amount = ContractMigration.get_six_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_six_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_six_level_references(nftID, i));
        }

        get_six_level_references[nftID] = nfts;
        six_level_references_recover[nftID] = true;
    }

    function recoverSevenLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !seven_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_seven_level_references[nftID];
        // uint256 amount = ContractMigration.get_seven_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_seven_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_seven_level_references(nftID, i));
        }

        get_seven_level_references[nftID] = nfts;
        seven_level_references_recover[nftID] = true;
    }

    function recoverEightLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !eight_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_eight_level_references[nftID];
        // uint256 amount = ContractMigration.get_eight_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_eight_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_eight_level_references(nftID, i));
        }

        get_eight_level_references[nftID] = nfts;
        eight_level_references_recover[nftID] = true;
    }

    function recoverNineLevelReferences(uint256 nftID) public {
        require(
            msg.sender == ownerOf(nftID) &&
                !nine_level_references_recover[nftID]
        );

        uint256[] storage nfts = get_nine_level_references[nftID];
        // uint256 amount = ContractMigration.get_nine_level_amount_reference(nftID);

        for (
            uint256 i = 0;
            i < ContractMigration.get_nine_level_amount_reference(nftID);
            i++
        ) {
            nfts.push(ContractMigration.get_nine_level_references(nftID, i));
        }

        get_nine_level_references[nftID] = nfts;
        nine_level_references_recover[nftID] = true;
    }

    // NFT
    function createNFT(
        string memory _name,
        string memory _inscription,
        string memory _valueProposal,
        string memory _uri,
        string memory _imageURL,
        uint256 _ref,
        uint256 _timestamp
    ) public {
        // Get Reference

        uint256 _reference = favourite_nft[ABLE.lastDonationFrom()];

        if (_ref != 0) {
            _reference = _ref;
        }

        if (_reference == 0) {
            _reference = 8;
        }

        require(_reference < _tokenIds.current());

        BUSD.transferFrom(msg.sender, address(this), PRICE);

        update_qualified_nfts(msg.sender);

        ABLE_SALE.try_to_swap(favourite_nft[msg.sender]);

        // Mint NFT
        uint256 tokenID = _tokenIds.current();
        _tokenIds.increment();
        _safeMint(msg.sender, tokenID);

        // Set URI
        _setTokenURI(tokenID, _uri);

        // Add information to the NFT
        get_nft_name[tokenID] = _name;
        get_nft_inscription[tokenID] = _inscription;
        get_nft_value_proposal[tokenID] = _valueProposal;
        get_nft_reference[tokenID] = _reference;

        get_nft_image_url[tokenID] = _imageURL;
        get_nft_timestamp_created[tokenID] = _timestamp;

        if (favourite_nft[msg.sender] == 0) {
            favourite_nft[msg.sender] = tokenID;
        }

        uint256[] storage myNFTS = get_my_nfts[msg.sender];
        myNFTS.push(tokenID);
        get_my_nfts[msg.sender] = myNFTS;

        // Increase the resources amount
        resourcesAmount += TO_DEVELOPMENT;

        // Increase Passive Rewards
        passiveReward[passiveRewardID] += 6 ether;

        // Distribute BUSD's in 9 generations
        distribute(tokenID, _reference, true);

        update(msg.sender);

        // Emit event
        // emit Mint(tokenID, block.timestamp, _name, _valueProposal, msg.sender);
    }

    function modifyNFT(
        string memory _name,
        string memory _inscription,
        string memory _valueProposal,
        uint256 _tokenID
    ) public {
        require(msg.sender == ownerOf(_tokenID));
        BUSD.transferFrom(msg.sender, address(this), PRICE);

        // Modify the NFT
        get_nft_name[_tokenID] = _name;
        get_nft_inscription[_tokenID] = _inscription;
        get_nft_value_proposal[_tokenID] = _valueProposal;

        // Increase the resources amount
        resourcesAmount += TO_DEVELOPMENT;

        // Increase Passive Rewards
        passiveReward[passiveRewardID] += 6 ether;

        // Distribute BUSD in 9 generations
        distribute(_tokenID, get_nft_reference[_tokenID], false);

        update(msg.sender);
    }

    // Rewards
    function claimReward(uint256 _tokenID) public {
        require(
            msg.sender == ownerOf(_tokenID) &&
                get_nft_balance_to_claim[_tokenID] > 0
        );

        BUSD.transfer(msg.sender, get_nft_balance_to_claim[_tokenID]);

        // // Emit events
        // emit Reward(
        //     _tokenID,
        //     get_nft_balance_to_claim[_tokenID],
        //     msg.sender,
        //     block.timestamp
        // );

        get_nft_rewards_claimed[_tokenID] += get_nft_balance_to_claim[_tokenID];
        get_nft_balance_to_claim[_tokenID] = 0;

        update(msg.sender);
    }

    function viewAmountToClaimPassiveReward(
        address wallet
    ) public view returns (uint256) {
        if (passiveRewardID == 0 || nfts_qualified == 0) return 0;
        if (nfts_qualified < balanceOf(wallet)) return 0;

        uint256 amount_raised = passiveReward[passiveRewardID - 1];
        uint256 amount_claimed = passiveRewardClaimed[passiveRewardID - 1];
        uint256 amount_to_claim = ((balanceOf(wallet) * amount_raised) /
            nfts_qualified);

        if (amount_to_claim > (amount_raised - amount_claimed)) {
            return (amount_raised - amount_claimed);
        }

        return amount_to_claim;
    }

    function viewAmountToClaimConstancyReward(
        address wallet
    ) public view returns (uint256) {
        // Formula:
        // Veces que gane el Premio Able * Cantidad recaudada / Veces que ganaron el Premio Able
        uint256 totalWinsSaverReward = ABLE.totalWinsSaverReward();
        uint256 winsSaverRewardOf = ABLE.winsSaverRewardOf(wallet);

        if (passiveRewardID == 0 || totalWinsSaverReward == 0) return 0;
        if (totalWinsSaverReward < winsSaverRewardOf) return 0;

        uint256 amount_raised = constancyReward[passiveRewardID - 1];
        uint256 amount_claimed = constancyRewardClaimed[passiveRewardID - 1];
        uint256 amount_to_claim = ((winsSaverRewardOf * amount_raised) /
            totalWinsSaverReward);

        if (amount_to_claim > (amount_raised - amount_claimed)) {
            return (amount_raised - amount_claimed);
        }

        return amount_to_claim;
    }

    function claimPassiveReward() public {
        require(
            passiveRewardID > 0 &&
                block.timestamp > timestampToClaimPassiveReward[msg.sender] &&
                ABLE.canReclaim(msg.sender)
        );

        uint256 amount = viewAmountToClaimPassiveReward(msg.sender);

        BUSD.transfer(msg.sender, amount);

        passiveRewardClaimed[passiveRewardID - 1] += amount;

        timestampToClaimPassiveReward[msg.sender] = block.timestamp + oneDay;

        update(msg.sender);

        // Emit events
        // emit PassiveReward(amount, msg.sender, block.timestamp);
    }

    function claimConstancyReward() public {
        require(
            passiveRewardID > 0 &&
                block.timestamp > timestampToClaimConstancyReward[msg.sender] &&
                ABLE.canReclaim(msg.sender) &&
                ABLE.winSaverReward(msg.sender) &&
                ABLE.totalWinsSaverReward() >= 2
        );

        uint256 amount = viewAmountToClaimConstancyReward(msg.sender);

        BUSD.transfer(msg.sender, amount);

        constancyRewardClaimed[passiveRewardID - 1] += amount;

        timestampToClaimConstancyReward[msg.sender] = block.timestamp + oneDay;

        update(msg.sender);

        // Emit Event
    }

    function claimResources() public {
        require(msg.sender == developmentWallet);

        BUSD.transfer(msg.sender, resourcesAmount);

        // Emit events
        // emit Resources(block.timestamp, resourcesAmount);

        resourcesAmount = 0;

        update(msg.sender);
    }

    // Read functions
    function getAmountOfNftMinted() public view returns (uint256) {
        return _tokenIds.current();
    }

    // Set Functions
    function setAbleAddress(address _ableAddress) public {
        require(msg.sender == developmentWallet);

        ABLE = ERC20(_ableAddress);
    }

    function setFavouriteNFT(uint256 id) public {
        require(_tokenIds.current() > id);
        favourite_nft[msg.sender] = id;
        update(msg.sender);
    }

    function changeCommunityWallet(address newAddress) public {
        require(msg.sender == communityWallet);

        communityWallet = newAddress;
    }

    // Booleans
    function nft_was_qualified(uint256 tokenID) public view returns (bool) {
        return
            ABLE.canReclaim(ownerOf(tokenID)) ||
            ABLE.qualifiedHistory(ownerOf(tokenID), ABLE.cycle() - 1);
    }

    // Update Functions
    function update_qualified_nfts(address wallet) private {
        if (is_qualified[wallet]) {
            nfts_qualified -= amount_nfts_considered[wallet];
            amount_nfts_considered[wallet] = 0;
            is_qualified[wallet] = false;
        }

        if (ABLE.canReclaim(wallet)) {
            nfts_qualified += balanceOf(wallet);
            amount_nfts_considered[wallet] = balanceOf(wallet);
            is_qualified[wallet] = true;
        }
    }

    function update_timestamp() private {
        if (block.timestamp > timeToNextReward) {
            if (
                passiveRewardID > 0 &&
                passiveReward[passiveRewardID - 1] >
                passiveRewardClaimed[passiveRewardID - 1]
            ) {
                passiveReward[passiveRewardID] += (passiveReward[
                    passiveRewardID - 1
                ] - passiveRewardClaimed[passiveRewardID - 1]);
            }

            if (
                passiveRewardID > 0 &&
                constancyReward[passiveRewardID - 1] >
                constancyRewardClaimed[passiveRewardID - 1]
            ) {
                constancyReward[passiveRewardID] += (constancyReward[
                    passiveRewardID - 1
                ] - constancyRewardClaimed[passiveRewardID - 1]);
            }

            passiveRewardID++;
            timeToNextReward = block.timestamp + oneDay;
        }
    }

    function update(address wallet) public {
        ABLE.updateFromSinergy(wallet);

        update_timestamp();

        update_qualified_nfts(wallet);
    }

    function updateFromAble(address wallet) public {
        update_timestamp();
        update_qualified_nfts(wallet);
    }

    function getAbleBalance(address wallet) public view returns (uint256) {
        return ABLE.balanceOf(wallet);
    }

    // SaleToken Public Functions
    function set_able_sale(SinergySale ableSale) public {
        require(msg.sender == developmentWallet);
        ABLE_SALE = ableSale;
    }

    function set_triple_sale(SinergySale tripleSale) public {
        require(msg.sender == developmentWallet);
        TRIPLE_SALE = tripleSale;
    }

    function set_passive_rewards(uint256 amount) public {
        require(
            msg.sender == address(ABLE_SALE) ||
                msg.sender == address(TRIPLE_SALE)
        );
        passiveReward[passiveRewardID] += amount;
    }

    function set_active_rewards(uint256 tokenID, uint256 amount) public {
        require(
            msg.sender == address(ABLE_SALE) ||
                msg.sender == address(TRIPLE_SALE)
        );
        get_nft_balance_to_claim[tokenID] += amount;
    }

    function set_constancy_reward(uint256 amount) public {
        require(
            msg.sender == address(ABLE_SALE) ||
                msg.sender == address(TRIPLE_SALE)
        );
        constancyReward[passiveRewardID] += amount;
    }

    // Private Functions

    // Distribute 9 generations
    function distribute(
        uint256 tokenID,
        uint256 _reference,
        bool created
    ) private {
        address owner;
        uint256 i = 0;
        while (i < 9) {
            if (created) setReferences(i, tokenID, _reference);

            owner = ownerOf(_reference);

            if (ABLE.canReclaim(owner)) {
                get_nft_balance_to_claim[_reference] += REWARD;
                total_stablecoin_earned[owner] += REWARD;
            } else {
                passiveReward[passiveRewardID] += REWARD;
                total_lost_income[owner] += REWARD;
                actual_lost_income[owner] = REWARD;
            }

            _reference = get_nft_reference[_reference];

            i++;
        }
    }

    function create_genesis_nfts() private {
        // Crear 8 NFTs para la billetera destinada a Desarrollo y Mantenimiento
        // Estos NFTs deben estar vinculados entre si
        uint256[] storage myNFTS = get_my_nfts[communityWallet];
        uint256[] storage new_nfts_recovered = recovered_nfts;

        for (uint256 i = 0; i < 9; i++) {
            _safeMint(communityWallet, i);

            recoverNFT(i);

            myNFTS.push(i);
            new_nfts_recovered.push(i);
            recovered_nfts_amount++;

            _setTokenURI(
                i,
                "ipfs://QmRi1DvgDu6zAJwpbURGNBBQTM82ZCNZAyTkEArbKZKm1U/0.json"
            );
        }

        get_my_nfts[communityWallet] = myNFTS;
        recovered_nfts = new_nfts_recovered;
    }

    function setReferences(uint256 i, uint256 tokenID, uint256 ref) private {
        if (i == 0) {
            get_first_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_first_level_references[ref];
            nftIDs.push(tokenID);
            get_first_level_references[ref] = nftIDs;

            return;
        }

        if (i == 1) {
            get_second_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_second_level_references[ref];
            nftIDs.push(tokenID);
            get_second_level_references[ref] = nftIDs;

            return;
        }

        if (i == 2) {
            get_third_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_third_level_references[ref];
            nftIDs.push(tokenID);
            get_third_level_references[ref] = nftIDs;

            return;
        }

        if (i == 3) {
            get_four_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_four_level_references[ref];
            nftIDs.push(tokenID);
            get_four_level_references[ref] = nftIDs;

            return;
        }

        if (i == 4) {
            get_five_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_five_level_references[ref];
            nftIDs.push(tokenID);
            get_five_level_references[ref] = nftIDs;

            return;
        }

        if (i == 5) {
            get_six_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_six_level_references[ref];
            nftIDs.push(tokenID);
            get_six_level_references[ref] = nftIDs;

            return;
        }

        if (i == 6) {
            get_seven_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_seven_level_references[ref];
            nftIDs.push(tokenID);
            get_seven_level_references[ref] = nftIDs;

            return;
        }

        if (i == 7) {
            get_eight_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_eight_level_references[ref];
            nftIDs.push(tokenID);
            get_eight_level_references[ref] = nftIDs;

            return;
        }

        if (i == 8) {
            get_nine_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            uint256[] storage nftIDs = get_nine_level_references[ref];
            nftIDs.push(tokenID);
            get_nine_level_references[ref] = nftIDs;

            return;
        }
    }

    // The following functions are overrides required by Solidity.

    function _burn(
        uint256 tokenId
    ) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(
        uint256 tokenId
    ) public view override(ERC721, ERC721URIStorage) returns (string memory) {
        return super.tokenURI(tokenId);
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address to, uint256 amount) external returns (bool);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
}

interface IERC20Metadata is IERC20 {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);
}

contract ERC20 is Context, IERC20, IERC20Metadata {
    // Migration Saver
    uint256 timestampToCloseMigration;
    mapping(address => bool) public isRecover;

    // ERC20 Standard
    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;
    uint256 private _totalSupply;
    string private _name;
    string private _symbol;

    uint256 public POTENCIAL = 9;

    uint256 public timeStableCoinReward = 6 minutes;

    // Saver
    uint256 public maxSupply = 369000000000 * 10 ** 18;
    uint256 public initialSupply = 369000000 * 10 ** 18;
    uint256 public devSupply = 1845000 * 10 ** 18;

    // Addresses
    address payable public communityWallet =
        payable(0xc8895f6f85D870589C42fd6d531c855bddD27B0f);
    address public managementWallet =
        0xc8895f6f85D870589C42fd6d531c855bddD27B0f;
    address public managementWallet2 =
        0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;
    address public devWallet = 0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;

    // Saver Reward
    mapping(address => bool) public isListedToClaimSaver;
    mapping(address => uint256) public cyclesOf;

    // ERC20's
    // Stable Coin
    ERC20 public USDC = ERC20(0x4E8F5dC8c0f21992116Aac2458b0Bded98E11F13); // USDC (6 decimals)
    uint256 public USDC_DECIMALS = 6;

    ERC20 public USDT = ERC20(0x17c3358F9Aa2D85E49d502EFBc27c9289ef913aA); // USDT (6 decimals)
    uint256 public USDT_DECIMALS = 6;

    ERC20 public BUSD = ERC20(0xB856De7DAFf71A0d7eAFD4CC22A7db6F762179de); // BUSD (18 decimals)
    uint256 public BUSD_DECIMALS = 18;

    // Contract Migration
    ERC20 public AbleMigration =
        ERC20(0xB13D289830F6512dFf4C6ce97f121F29bD400E39);
    ERC20 public TripleMigration =
        ERC20(0x38e43FCEEE68373e08a30714123010b8d841364d);
    SinergyMigration ContractMigration =
        SinergyMigration(0xEa063b5A744616a161272a013a626A1cBD80Ee1B);

    // ERC721
    ERC721 public SinergyBronze;
    ERC721 public SinergySilver;
    ERC721 public SinergyGold;

    // Sell List
    SinergySale public ABLE_SALE;

    // Cycles
    uint256 public cycle = 1;
    mapping(address => uint256) public cycleToCheck;
    mapping(address => uint256) public cycleToSaverReward;
    uint256 public CYCLES_FOR_SAVER_REWARD = 3;

    // Saver Reward
    mapping(address => uint256) public balanceOfWins_SaverReward;
    mapping(address => bool) public winSaverReward;
    mapping(address => uint256) public winsSaverRewardOf;
    mapping(address => uint256) public total_saver_earned_of;
    uint256 public totalWinsSaverReward;
    uint256 public total_saver_distributed;
    address[] public wallet_winners;

    // Stable Coin Reward
    uint256 public minAmountToQualify = 3 * 10 ** 18;
    uint256 public rewardID = 1;
    uint256 public rewardIDonClaim;
    uint256 public totalStableCoinDistribute;

    mapping(uint256 => uint256) public rewardAmount; // rewardAmount[rewardID] => Amount Raised
    mapping(uint256 => uint256) public rewardAmountClaimed; // rewardAmount[rewardID] => Amount Claimed

    mapping(uint256 => uint256) public timeOpenClaimReward; // timeOpenClaimReward[rewardID] => timestamp

    mapping(address => mapping(uint256 => bool)) public holderClaimed; // holderClaimed[wallet][rewardID] => bool

    mapping(address => uint256) public stableCoinEarned;
    mapping(address => uint256) public stableCoinEarnedByAbleReward;

    mapping(address => bool) public isQualified; // isQualified[wallet] => bool

    mapping(address => uint256) public claimFrom;

    // Donations
    uint256 public totalDonationBalance;
    uint256 public qualifiedDonationBalance;
    uint256 public totalDonations;
    uint256 public wallets_with_donation_balance;
    uint256 public total_qualified_wallets;
    mapping(address => uint256) public donationBalance;
    mapping(address => uint256) public allDonatesOf;
    uint256 public lastDonationTimestamp;
    address public lastDonationFrom;

    // Donations per day
    mapping(address => mapping(uint256 => uint256)) public donatedByDayOf; // donatedByDayOf[wallet][cycle] => amount donated
    mapping(address => mapping(uint256 => uint256))
        public donationBalancePerCycle;

    // Savings
    mapping(address => mapping(uint256 => uint256)) public usdcRecord;
    mapping(address => uint256) public lastAmountUSDC;

    mapping(address => mapping(uint256 => uint256)) public usdtRecord;
    mapping(address => uint256) public lastAmountUSDT;

    // Holders
    uint256 public totalHolders;
    uint256 public qualifiedHolders;
    mapping(address => bool) public isHolder;
    mapping(address => string) public personalPurpose;
    mapping(address => string) public communityPurpose;

    // Resources for Admin
    uint256 public total_raised_for_admin; // Total amount raised for admin

    // Videos
    bool public sort; // true => sorted | false => not sorted
    uint256 public videoID;
    mapping(uint256 => string) public youtubeID;

    mapping(uint256 => string) public firstQuestion;
    mapping(uint256 => string) public secondQuestion;
    mapping(uint256 => string) public thirdQuestion;

    mapping(uint256 => string) public firstRealAnswer;
    mapping(uint256 => string) public secondRealAnswer;
    mapping(uint256 => string) public thirdRealAnswer;

    mapping(uint256 => string) public firstFakeAnswer1;
    mapping(uint256 => string) public secondFakeAnswer1;
    mapping(uint256 => string) public thirdFakeAnswer1;

    mapping(uint256 => string) public firstFakeAnswer2;
    mapping(uint256 => string) public secondFakeAnswer2;
    mapping(uint256 => string) public thirdFakeAnswer2;

    mapping(address => mapping(uint256 => bool)) public videoAnswerOf; // answerOf[wallet][cycle] => true

    // Qualified
    // qualified[wallet][cycle] => bool
    mapping(address => mapping(uint256 => bool)) public qualifiedSinergy;
    mapping(address => mapping(uint256 => bool)) public qualifiedSaver;
    mapping(address => mapping(uint256 => bool)) public qualifiedUSDC;
    mapping(address => mapping(uint256 => bool)) public qualifiedUSDT;
    mapping(address => mapping(uint256 => bool)) public qualifiedBDD;
    mapping(address => mapping(uint256 => bool)) public qualifiedDonatedPerDay;
    mapping(address => mapping(uint256 => bool)) public qualifiedVideo;
    mapping(address => mapping(uint256 => bool)) public qualifiedHistory;

    // Informacion
    string public managementInfo;

    // Events
    event ClaimBUSD(
        uint256 indexed date,
        uint256 amount,
        address indexed wallet
    );

    event ClaimAble(
        uint256 indexed date,
        uint256 amount,
        address indexed wallet
    );

    event AnswerVideo(uint256 indexed date, bool res, address indexed wallet);

    event Update(uint256 indexed date, address indexed wallet);

    // Nuevos eventos
    event AbleRewardQualification(
        uint256 indexed date,
        address indexed wallet,
        bool status
    ); // true => te has enlistado para el premio able || false => te has descalificado del premio able

    event UserQualification(
        uint256 indexed date,
        address indexed wallet,
        bool status
    );

    event CycleChange(uint256 indexed date, uint256 indexed cycle);

    event CloseCycle(
        address indexed wallet,
        uint256 cycle,
        bool qualifiedSinergy,
        bool qualifiedUSDT,
        bool qualifiedUSDC,
        bool qualifiedSaver,
        bool qualifiedBDD,
        bool qualifiedDonatedPerDay,
        bool qualifiedVideo
    );

    event Points(
        address indexed wallet,
        uint256 cycle,
        uint256 amount,
        bool increase
    );

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;

        timeOpenClaimReward[rewardID] = block.timestamp + timeStableCoinReward;

        timestampToCloseMigration = block.timestamp + 30 days;

        // Se mintea el 0.1% del totalSupply (369.000.000 ABLE)
        _mint(communityWallet, initialSupply - devSupply);
        _mint(devWallet, devSupply);

        isHolder[communityWallet] = true;
        isHolder[devWallet] = true;

        totalHolders = 2;
        qualifiedHolders = 2;
        total_qualified_wallets = 2;
    }

    // Recover Saver
    function get_able_to_recover(address wallet) public view returns (uint256) {
        bool was_active = AbleMigration.canReclaim(wallet);
        uint256 _cycle = AbleMigration.cycle();
        uint256 i;
        uint256 default_amount = AbleMigration.balanceOf(wallet) +
            TripleMigration.balanceOf(wallet);

        while (!was_active && i < 69) {
            was_active = AbleMigration.qualifiedHistory(wallet, _cycle - i);
            i++;
        }
        if (was_active) {
            return (default_amount + AbleMigration.donationBalance(wallet));
        }

        return default_amount;
    }

    function migrate() public {
        require(block.timestamp < timestampToCloseMigration);
        require(!isRecover[msg.sender]);

        // Recover Donation Balance
        donationBalance[msg.sender] += AbleMigration.donationBalance(
            msg.sender
        );
        totalDonationBalance += donationBalance[msg.sender];
        allDonatesOf[msg.sender] += AbleMigration.allDonatesOf(msg.sender);


        // Recover Purposes
        personalPurpose[msg.sender] = AbleMigration.personalPurpose(msg.sender);
        communityPurpose[msg.sender] = AbleMigration.communityPurpose(
            msg.sender
        );

        // Recover SAVF (Last Saver Fast)
        _mint(msg.sender, get_able_to_recover(msg.sender));

        if (AbleMigration.balanceOf(msg.sender) > 0 && !isHolder[msg.sender]) {
            totalHolders++;
            isHolder[msg.sender] = true;
        }

        // Recover Qualified Donation Balance
        if (canReclaim(msg.sender) && !isQualified[msg.sender]) {
            qualifiedDonationBalance += donationBalance[msg.sender];
            isQualified[msg.sender] = true;
            qualifiedHolders++;
            emit UserQualification(block.timestamp, msg.sender, true);
        }

        isRecover[msg.sender] = true;
    }

    function burn_bdd(uint256 amount) public {
        require(donationBalance[msg.sender] >= amount);

        reduceDonationBalance(msg.sender, amount);
    }

    function claim() public {
        uint256 amountRaised = rewardAmount[rewardIDonClaim];
        uint256 amountClaimed = rewardAmountClaimed[rewardIDonClaim];

        require(!holderClaimed[msg.sender][rewardIDonClaim]);

        require(rewardIDonClaim >= claimFrom[msg.sender]);
        require(canReclaim(msg.sender));

        uint256 stableCoinToClaim = viewClaimStableCoin(msg.sender);

        require(stableCoinToClaim > 0);

        require(amountRaised >= (amountClaimed + stableCoinToClaim));

        require(donationBalance[msg.sender] >= (stableCoinToClaim / POTENCIAL));

        require(BUSD.transfer(msg.sender, stableCoinToClaim));

        reduceDonationBalance(msg.sender, stableCoinToClaim / POTENCIAL);

        rewardAmountClaimed[rewardIDonClaim] += stableCoinToClaim;
        holderClaimed[msg.sender][rewardIDonClaim] = true;
        totalStableCoinDistribute += stableCoinToClaim;
        stableCoinEarned[msg.sender] += stableCoinToClaim;
        stableCoinEarnedByAbleReward[msg.sender] += stableCoinToClaim;

        _updateALL(msg.sender);

        // Emit events
        emit ClaimBUSD(block.timestamp, stableCoinToClaim, msg.sender);
    }

    function claimSaver() public {
        _updateALL(msg.sender);
        require((_totalSupply + donationBalance[msg.sender]) < maxSupply);
        require(
            canReclaimSaver(msg.sender),
            "You are not qualified to claim SAVER."
        );

        // Nueva version
        require(
            cycleToSaverReward[msg.sender] < cycle,
            "You have to wait 30 days to claim your SAVER."
        );

        // Emit events
        emit ClaimAble(
            block.timestamp,
            donationBalance[msg.sender],
            msg.sender
        );

        _mint(msg.sender, donationBalance[msg.sender]);

        isListedToClaimSaver[msg.sender] = false;

        if (!winSaverReward[msg.sender]) {
            address[] storage winners = wallet_winners;
            winners.push(msg.sender);
            wallet_winners = winners;
        }

        winSaverReward[msg.sender] = true;

        winsSaverRewardOf[msg.sender]++;
        totalWinsSaverReward++;

        balanceOfWins_SaverReward[msg.sender]++;

        total_saver_distributed += donationBalance[msg.sender];
        total_saver_earned_of[msg.sender] += donationBalance[msg.sender];

        stableCoinEarnedByAbleReward[msg.sender] = 0;

        updateTimestampRewards();
    }

    // Video

    function uploadVideoAndFirstQuestion(
        string memory _youtubeID,
        string memory _firstQuestion,
        string memory _firstRealAnswer,
        string memory _firstFakeAnswer1,
        string memory _firstFakeAnswer2
    ) public {
        require(
            msg.sender == managementWallet ||
                msg.sender == managementWallet2 ||
                msg.sender == communityWallet,
            "You are not qualified to call this function"
        );
        youtubeID[videoID] = _youtubeID;

        firstQuestion[videoID] = _firstQuestion;

        firstRealAnswer[videoID] = _firstRealAnswer;

        firstFakeAnswer1[videoID] = _firstFakeAnswer1;

        firstFakeAnswer2[videoID] = _firstFakeAnswer2;

        videoID++;
    }

    function uploadSecondQuestion(
        string memory _secondQuestion,
        string memory _secondRealAnswer,
        string memory _secondFakeAnswer1,
        string memory _secondFakeAnswer2
    ) public {
        require(
            msg.sender == managementWallet ||
                msg.sender == managementWallet2 ||
                msg.sender == communityWallet,
            "You are not qualified to call this function"
        );

        secondQuestion[videoID - 1] = _secondQuestion;

        secondRealAnswer[videoID - 1] = _secondRealAnswer;

        secondFakeAnswer1[videoID - 1] = _secondFakeAnswer1;

        secondFakeAnswer2[videoID - 1] = _secondFakeAnswer2;
    }

    function uploadThirdQuestion(
        string memory _thirdQuestion,
        string memory _thirdRealAnswer,
        string memory _thirdFakeAnswer1,
        string memory _thirdFakeAnswer2
    ) public {
        require(
            msg.sender == managementWallet ||
                msg.sender == managementWallet2 ||
                msg.sender == communityWallet,
            "You are not qualified to call this function"
        );

        thirdQuestion[videoID - 1] = _thirdQuestion;

        thirdRealAnswer[videoID - 1] = _thirdRealAnswer;

        thirdFakeAnswer1[videoID - 1] = _thirdFakeAnswer1;

        thirdFakeAnswer2[videoID - 1] = _thirdFakeAnswer2;
    }

    function answerVideo(
        string memory answer1,
        string memory answer2,
        string memory answer3,
        uint256 _videoID
    ) public {
        bool first = (keccak256(abi.encodePacked((answer1))) ==
            keccak256(abi.encodePacked((firstRealAnswer[_videoID]))));
        bool second = (keccak256(abi.encodePacked((answer2))) ==
            keccak256(abi.encodePacked((secondRealAnswer[_videoID]))));
        bool third = (keccak256(abi.encodePacked((answer3))) ==
            keccak256(abi.encodePacked((thirdRealAnswer[_videoID]))));

        videoAnswerOf[msg.sender][cycle] = first && second && third;

        emit AnswerVideo(block.timestamp, first && second && third, msg.sender);

        _updateALL(msg.sender);
    }

    function changeSorted() public {
        require(
            msg.sender == communityWallet ||
                msg.sender == managementWallet ||
                msg.sender == managementWallet2,
            "You are not qualified to call this function"
        );
        sort = !sort;
    }

    function changeUSDC(address _newCoin, uint256 _decimals) public {
        require(
            msg.sender == communityWallet || msg.sender == devWallet,
            "You are not able to call this function"
        );
        USDC = ERC20(_newCoin);
        USDC_DECIMALS = _decimals;
    }

    function changeUSDT(address _newCoin, uint256 _decimals) public {
        require(
            msg.sender == communityWallet || msg.sender == devWallet,
            "You are not able to call this function"
        );
        USDT = ERC20(_newCoin);
        USDT_DECIMALS = _decimals;
    }

    function changeBUSD(address _newCoin, uint256 _decimals) public {
        require(
            msg.sender == communityWallet || msg.sender == devWallet,
            "You are not able to call this function"
        );
        BUSD = ERC20(_newCoin);
        BUSD_DECIMALS = _decimals;
    }

    function changeCommunityWallet(address newAddress) public {
        require(
            msg.sender == communityWallet,
            "You are not qualified to call this function."
        );

        communityWallet = payable(newAddress);
    }

    function viewClaimStableCoin(address wallet) public view returns (uint256) {
        if (qualifiedDonationBalance == 0 || !canReclaim(wallet)) return 0;

        uint256 amount = ((rewardAmount[rewardIDonClaim] *
            donationBalance[wallet]) / qualifiedDonationBalance);
        uint256 amountClaimed = rewardAmountClaimed[rewardIDonClaim];
        uint256 amountRaised = rewardAmount[rewardIDonClaim];

        if (amountRaised < (amountClaimed + amount)) {
            amount = (amountRaised - amountClaimed);
        }

        if (amount > (donationBalance[wallet] * POTENCIAL))
            return donationBalance[wallet] * POTENCIAL;

        return amount;
    }

    function qualifiedForBDD(address wallet) public view returns (bool) {
        return (donationBalance[wallet] >= minAmountToQualify);
    }

    function qualifiedForSAVER(address wallet) public view returns (bool) {
        return (_balances[wallet] > donationBalance[wallet]);
    }

    function qualifiedForUSDT(address wallet) public view returns (bool) {
        return (getBalanceOfUSDT(wallet) > donationBalance[wallet]);
    }

    function qualifiedForUSDC(address wallet) public view returns (bool) {
        return (getBalanceOfUSDC(wallet) > donationBalance[wallet]);
    }

    function qualifiedForDonatePerDay(
        address wallet
    ) public view returns (bool) {
        if (donationBalance[wallet] == 0) return false;

        if (cycle > 1) {
            return (donationBalancePerCycle[wallet][cycle - 1] >=
                getZeroPointNinePercent(
                    donationBalancePerCycle[wallet][cycle - 2]
                ));
        }

        return true;
    }

    function getSavingsLimit(address wallet) public view returns (uint256) {
        return ((usdcRecord[wallet][cycle - 1] * 100369) / 100000);
    }

    function getZeroPointNinePercent(
        uint256 amount
    ) public pure returns (uint256) {
        return (amount * 1009) / 1000;
    }

    function qualifiedForVideo(address wallet) public view returns (bool) {
        return videoAnswerOf[wallet][cycle - 1];
    }

    function getMinAmountToDonate(
        address wallet
    ) public view returns (uint256) {
        if (
            getZeroPointNinePercent(
                donationBalancePerCycle[wallet][cycle - 1]
            ) > donationBalance[wallet]
        ) {
            return
                getZeroPointNinePercent(
                    donationBalancePerCycle[wallet][cycle - 1]
                ) - donationBalance[wallet];
        }

        return 0;
    }

    function qualifiedForSinergy(address wallet) public view returns (bool) {
        bool bronze = false;
        bool silver = false;
        bool gold = false;

        if (SinergyBronze != ERC721(address(0))) {
            bronze = SinergyBronze.balanceOf(wallet) > 0;
        }

        if (SinergySilver != ERC721(address(0))) {
            silver = SinergySilver.balanceOf(wallet) > 0;
        }

        if (SinergyGold != ERC721(address(0))) {
            gold = SinergyGold.balanceOf(wallet) > 0;
        }

        return (bronze || silver || gold);
    }

    function canReclaim(address wallet) public view returns (bool) {
        if (wallet == communityWallet || wallet == devWallet) return true;

        return (qualifiedSinergy[wallet][cycle - 1] &&
            qualifiedUSDT[wallet][cycle - 1] &&
            qualifiedUSDC[wallet][cycle - 1] &&
            qualifiedSaver[wallet][cycle - 1] &&
            qualifiedBDD[wallet][cycle - 1] &&
            qualifiedDonatedPerDay[wallet][cycle - 1] &&
            qualifiedVideo[wallet][cycle - 1]);
    }

    function canReclaimSaver(address wallet) public view returns (bool) {
        return (canReclaim(wallet) && isListedToClaimSaver[wallet]);
    }

    // Esta funcion la agregamos porque fallaba el premio able (28-10-2022)
    // Pero luego nos dimos cuenta que estaba bien
    function canReclaimAble(address wallet) public view returns (bool) {
        bool res = true;

        if (cycle < CYCLES_FOR_SAVER_REWARD) return false;

        for (uint256 i = cycle - CYCLES_FOR_SAVER_REWARD; i < cycle; i++) {
            res = res && qualifiedHistory[wallet][i];
        }

        return res;
    }

    /*
        Si los decimales son distintos a 18, entonces para tratar a todos los tokens con 18 decimales retornamos
        el balance que dice el contrato del token multiplicado por 10 elevado a la diferencia de 18 y los decimales
        de ese token.
        Por ejemplo: USDC (6 Decimales)
        Como sus decimales son distintos a 18, hara lo siguiente. El balance que retorne el contrato de USDC en
        6 decimales le agregara 12 decimales mas. (18 - DECIMALS).
        Para asi finalmente tratarlo como un token de 18 decimales.
    */

    function getBalanceOfUSDC(address wallet) public view returns (uint256) {
        if (USDC_DECIMALS == 18) {
            return USDC.balanceOf(wallet);
        }
        return USDC.balanceOf(wallet) * 10 ** (18 - USDC_DECIMALS);
    }

    function getBalanceOfUSDT(address wallet) public view returns (uint256) {
        if (USDT_DECIMALS == 18) {
            return USDT.balanceOf(wallet);
        }
        return USDT.balanceOf(wallet) * 10 ** (18 - USDT_DECIMALS);
    }

    function getBalanceOfBUSD(address wallet) public view returns (uint256) {
        if (BUSD_DECIMALS == 18) {
            return BUSD.balanceOf(wallet);
        }
        return BUSD.balanceOf(wallet) * 10 ** (18 - BUSD_DECIMALS);
    }

    function updateTimestampRewards() public {
        if (block.timestamp > timeOpenClaimReward[rewardID]) {
            // If someone forgot to claim, this reward will appear on the next reward
            rewardAmount[rewardID] += (rewardAmount[rewardIDonClaim] -
                rewardAmountClaimed[rewardIDonClaim]);

            cycle++;
            emit CycleChange(block.timestamp, cycle);

            rewardIDonClaim = rewardID;
            rewardID++;

            // Update times to claim
            timeOpenClaimReward[rewardID] =
                block.timestamp +
                timeStableCoinReward;
        }
    }

    function updateALL(address wallet) public {
        updateTimestampRewards();
        updateSavings(wallet);
        updateQualifiedDonationBalance(wallet);
        checkDay(wallet);
        checkSaverReward(wallet);

        if (SinergyBronze != ERC721(address(0))) {
            SinergyBronze.updateFromAble();
        }

        if (SinergySilver != ERC721(address(0))) {
            SinergySilver.updateFromAble();
        }

        if (SinergyGold != ERC721(address(0))) {
            SinergyGold.updateFromAble();
        }

        emit Update(block.timestamp, wallet);
    }

    function _updateALL(address wallet) private {
        updateTimestampRewards();
        updateSavings(wallet);
        updateQualifiedDonationBalance(wallet);
        checkDay(wallet);
        checkSaverReward(wallet);

        if (SinergyBronze != ERC721(address(0))) {
            SinergyBronze.updateFromAble();
        }

        if (SinergySilver != ERC721(address(0))) {
            SinergySilver.updateFromAble();
        }

        if (SinergyGold != ERC721(address(0))) {
            SinergyGold.updateFromAble();
        }
    }

    function updateFromSinergy(address wallet) public {
        updateTimestampRewards();
        updateSavings(wallet);
        updateQualifiedDonationBalance(wallet);
        checkDay(wallet);
        checkSaverReward(wallet);
    }

    function setPersonalPurpose(string memory _str) public {
        personalPurpose[msg.sender] = _str;
    }

    function setCommunityPurpose(string memory _str) public {
        communityPurpose[msg.sender] = _str;
    }

    function withdrawAllFunds() public {
        require(
            (block.timestamp - lastDonationTimestamp) > 1 days,
            "The contract is still working"
        );
        require(
            msg.sender == communityWallet,
            "You are not qualified to call to this function"
        );

        require(
            BUSD.transfer(msg.sender, address(this).balance),
            "Cannot pay StableCoin"
        );
    }

    function setManagementInfo(string memory info) public {
        require(
            msg.sender == managementWallet || msg.sender == communityWallet,
            "You are not qualified to call this function"
        );

        managementInfo = info;
    }

    function changeManagementWallet(address _managementWallet) public {
        require(
            msg.sender == communityWallet,
            "You are not qualified to call this function"
        );

        managementWallet = _managementWallet;
    }

    function changeManagementWallet2(address _managementWallet) public {
        require(
            msg.sender == communityWallet,
            "You are not qualified to call this function"
        );

        managementWallet2 = _managementWallet;
    }

    function set_potencial(uint256 _potencial) public {
        require(
            msg.sender == communityWallet || msg.sender == devWallet,
            "You are not qualified to call this function."
        );
        POTENCIAL = _potencial;
    }

    function setSinergyBronze(address _sinergyBronze) public {
        require(
            msg.sender == devWallet,
            "You are not qualified to call this function"
        );

        SinergyBronze = ERC721(_sinergyBronze);
    }

    function setSinergySilver(address _sinergySilver) public {
        require(
            msg.sender == devWallet,
            "You are not qualified to call this function"
        );

        SinergySilver = ERC721(_sinergySilver);
    }

    function setSinergyGold(address _sinergyGold) public {
        require(
            msg.sender == devWallet,
            "You are not qualified to call this function"
        );

        SinergyGold = ERC721(_sinergyGold);
    }

    function setSinergySell(SinergySale _ableSale) public {
        require(msg.sender == devWallet);
        ABLE_SALE = _ableSale;
    }

    // Private funcs
    function updateQualifiedDonationBalanceAfterDonate(
        address wallet,
        uint256 amount
    ) private {
        bool previousStatus = isQualified[wallet];

        if (isQualified[wallet]) {
            qualifiedDonationBalance -= donationBalance[wallet];
            isQualified[wallet] = false;
            total_qualified_wallets--;
            qualifiedHolders--;
        }

        if (donationBalance[wallet] == 0) {
            wallets_with_donation_balance++;
        }

        donationBalance[wallet] += amount;
        totalDonationBalance += amount;

        if (canReclaim(wallet)) {
            qualifiedDonationBalance += donationBalance[wallet];
            isQualified[wallet] = true;
            total_qualified_wallets++;
            qualifiedHolders++;
        }

        if (previousStatus != isQualified[wallet]) {
            emit UserQualification(block.timestamp, wallet, !previousStatus);
        }
    }

    function updateQualifiedDonationBalance(address wallet) private {
        bool previousStatus = isQualified[wallet];

        if (isQualified[wallet]) {
            qualifiedDonationBalance -= donationBalance[wallet];
            isQualified[wallet] = false;
            total_qualified_wallets--;
            qualifiedHolders--;
        }

        if (canReclaim(wallet)) {
            qualifiedDonationBalance += donationBalance[wallet];
            isQualified[wallet] = true;
            total_qualified_wallets++;
            qualifiedHolders++;
        }

        if (previousStatus != isQualified[wallet]) {
            emit UserQualification(block.timestamp, wallet, !previousStatus);
        }
    }

    function updateSavings(address wallet) private {
        uint256 last_saving_amount = lastAmountUSDC[wallet] +
            lastAmountUSDT[wallet];
        uint256 actual_saving_amount = getBalanceOfUSDC(wallet) +
            getBalanceOfUSDT(wallet);

        if (actual_saving_amount < last_saving_amount) {
            uint256 dif = last_saving_amount - actual_saving_amount;

            if (dif > donationBalance[wallet]) {
                reduceDonationBalance(wallet, donationBalance[wallet]);
            } else {
                reduceDonationBalance(wallet, dif);
            }
        }
    }

    function checkSaverReward(address wallet) private {
        if (!canReclaim(wallet) && isListedToClaimSaver[wallet]) {
            isListedToClaimSaver[wallet] = false;
            emit AbleRewardQualification(block.timestamp, wallet, false);
            return;
        }

        if (canReclaim(wallet) && !isListedToClaimSaver[wallet]) {
            isListedToClaimSaver[wallet] = true;
            cycleToSaverReward[wallet] = cycle + CYCLES_FOR_SAVER_REWARD;
            emit AbleRewardQualification(block.timestamp, wallet, true);
            return;
        }
    }

    // antes llamada checkDonatedByDay
    function checkDay(address wallet) private {
        if (cycle >= cycleToCheck[wallet]) {
            cycleToCheck[wallet] = cycle + 1;

            lastAmountUSDC[wallet] = getBalanceOfUSDC(wallet);
            lastAmountUSDT[wallet] = getBalanceOfUSDT(wallet);

            usdcRecord[wallet][cycle] = lastAmountUSDC[wallet];
            usdtRecord[wallet][cycle] = lastAmountUSDT[wallet];

            donationBalancePerCycle[wallet][cycle - 1] = donationBalance[
                msg.sender
            ];
            qualifiedSinergy[wallet][cycle - 1] = qualifiedForSinergy(wallet);
            qualifiedSaver[wallet][cycle - 1] = qualifiedForSAVER(wallet);
            qualifiedUSDT[wallet][cycle - 1] = qualifiedForUSDT(wallet);
            qualifiedUSDC[wallet][cycle - 1] = qualifiedForUSDC(wallet);
            qualifiedBDD[wallet][cycle - 1] = qualifiedForBDD(wallet);
            qualifiedDonatedPerDay[wallet][
                cycle - 1
            ] = qualifiedForDonatePerDay(wallet);
            qualifiedVideo[wallet][cycle - 1] = qualifiedForVideo(wallet);

            qualifiedHistory[wallet][cycle - 1] = canReclaim(wallet);

            emit CloseCycle(
                wallet,
                cycle - 1,
                qualifiedSinergy[wallet][cycle - 1],
                qualifiedUSDT[wallet][cycle - 1],
                qualifiedUSDC[wallet][cycle - 1],
                qualifiedSaver[wallet][cycle - 1],
                qualifiedBDD[wallet][cycle - 1],
                qualifiedDonatedPerDay[wallet][cycle - 1],
                qualifiedVideo[wallet][cycle - 1]
            );
        }
    }

    // Esta nueva funcion la tiene que llamar SinergySale cada vez que alguien compra ABLE
    function incrementDonationBalance(
        uint256 amount_spended,
        address wallet
    ) public {
        require(msg.sender == address(ABLE_SALE));
        updateQualifiedDonationBalanceAfterDonate(wallet, amount_spended);
        _updateALL(wallet);
        if (canReclaim(wallet)) {
            lastDonationFrom = msg.sender;
        }
        rewardAmount[rewardID] += (amount_spended / 3);
        allDonatesOf[wallet] += amount_spended;
        donatedByDayOf[wallet][cycle] += amount_spended;
        claimFrom[wallet] = rewardID;
        totalDonations++;

        total_raised_for_admin += (amount_spended / 3);

        lastDonationTimestamp = block.timestamp;

        // Emit Event
        emit Points(wallet, cycle, amount_spended, true);
    }

    function reduceDonationBalance(address wallet, uint256 amount) private {
        bool previousStatus = isQualified[wallet];

        if (isQualified[wallet]) {
            qualifiedDonationBalance -= donationBalance[wallet];
            isQualified[wallet] = false;
            total_qualified_wallets--;
            qualifiedHolders--;
        }

        donationBalance[wallet] -= amount;
        totalDonationBalance -= amount;

        if (donationBalance[wallet] == 0) {
            wallets_with_donation_balance--;
        }

        if (canReclaim(wallet)) {
            qualifiedDonationBalance += donationBalance[wallet];
            isQualified[wallet] = true;
            total_qualified_wallets++;
            qualifiedHolders++;
        }

        if (previousStatus != isQualified[wallet]) {
            emit UserQualification(block.timestamp, wallet, !previousStatus);
        }

        // Emit Event
        emit Points(wallet, cycle, amount, false);
    }

    // Funcs Private view

    // Funcs IERC20

    function name() public view virtual override returns (string memory) {
        return _name;
    }

    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(
        address account
    ) public view virtual override returns (uint256) {
        return _balances[account];
    }

    function transfer(
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    function allowance(
        address owner,
        address spender
    ) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(
        address spender,
        uint256 amount
    ) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    function increaseAllowance(
        address spender,
        uint256 addedValue
    ) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, _allowances[owner][spender] + addedValue);
        return true;
    }

    function decreaseAllowance(
        address spender,
        uint256 subtractedValue
    ) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = _allowances[owner][spender];
        require(
            currentAllowance >= subtractedValue,
            "ERC20: decreased allowance below zero"
        );
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        if (!isHolder[to]) {
            totalHolders++;
            isHolder[to] = true;
        }

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

        if (_balances[from] == 0) {
            totalHolders--;
            isHolder[from] = false;
        }

        _updateALL(from);
        _updateALL(to);

        updateQualifiedDonationBalance(from);
        updateQualifiedDonationBalance(to);

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

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

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

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

    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

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

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

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

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

    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

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

    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(
                currentAllowance >= amount,
                "ERC20: insufficient allowance"
            );
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

contract SinergySale {
    // Constants
    uint256 public constant TIME_OF_CYCLE = 6 minutes;

    uint256 public MAX_AMOUNT_SELL_TOKEN = 90 ether;
    uint256 public MIN_AMOUNT_SELL_TOKEN = 9 ether;
    uint256 public TOKEN_PRICE = 3;
    uint256 public LIMIT_POST_BY_CYCLE = 1;

    // Global Variables
    uint256 public TOTAL_TOKENS_SOLD;
    mapping(uint256 => uint256) public tokens_sold_by_cycle;

    // ERC20 Contracts
    ERC20 public ABLE;
    ERC20 public TOKEN;
    ERC20 public BUSD;

    // ERC721 Contract
    Sinergy public SinergyContract =
        Sinergy(0x508c132EE7cBb4A666E661634F85B59158eaDB4B);

    // Wallets
    address payable public communityWallet =
        payable(0xc8895f6f85D870589C42fd6d531c855bddD27B0f);
    address public dev_wallet = 0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;

    // Sell List
    uint256[] public sell_list;
    mapping(uint256 => bool) public is_in_sell_list;
    mapping(address => uint256) public timestamp_last_post_sell;
    mapping(address => uint256) public amount_of_post_of;

    // Driven List
    uint256[] public driven_list;
    mapping(uint256 => bool) public is_in_driven_list;
    mapping(address => uint256) public turns_in_driven_list_of;

    // Turn of pick
    uint256 public turn; // 0 y 1 => Driven List ||| 2 => Sell List

    // Amount on Sell
    uint256 public total_selling_amount;
    mapping(uint256 => uint256) public selling_amount_of;
    mapping(address => uint256) public post_count_of;

    // User Data
    mapping(address => uint256) public amount_sold_of;

    // Events
    event SellList(uint256 indexed nft_id, bool comeIn, bool driven);

    event SellToken(
        uint256 indexed nft_id,
        address indexed buyer,
        address indexed seller,
        uint256 amount
    );

    event SwapList(uint256 indexed nft_id);

    event BackToQueue(uint256 indexed nft_id, uint256 posAnt, uint256 posAct);

    // Constructor
    constructor(ERC20 _able, ERC20 _busd, ERC20 _token) {
        ABLE = _able;
        TOKEN = _token;
        BUSD = _busd;
    }

    // Public Methods
    function sell(uint256 _amount, uint256 _tokenID) public {
        require(
            _amount >= MIN_AMOUNT_SELL_TOKEN,
            "The amount to sell have to be more or equal than 9 and less or equal than 90."
        );
        require(
            (selling_amount_of[_tokenID] + _amount) <= MAX_AMOUNT_SELL_TOKEN,
            "The amount to sell have to be more or equal than 9 and less or equal than 90."
        );
        require(
            SinergyContract.ownerOf(_tokenID) == msg.sender,
            "You are not the owner of this NFT."
        );
        require(
            !is_selling(_tokenID),
            "You are already selling tokens on SinergySell"
        );
        require(
            TOKEN.transferFrom(msg.sender, address(this), _amount),
            "Transfer fails."
        );
        require(
            block.timestamp > timestamp_last_post_sell[msg.sender],
            "You have to wait to post another sell."
        );

        selling_amount_of[_tokenID] += _amount;
        total_selling_amount += _amount;
        timestamp_last_post_sell[msg.sender] = block.timestamp + TIME_OF_CYCLE;

        if (can_be_in_driven_list(msg.sender)) {
            set_nft_to_driven_list(_tokenID);
            turns_in_driven_list_of[msg.sender]++;
        } else {
            set_nft_to_sell_list(_tokenID);
        }
    }

    function buy(uint256 _amount, bool incrementBDD) public {
        require(_amount <= total_selling_amount);
        // Transferimos los BUSD a este contrato
        BUSD.transferFrom(msg.sender, address(this), _amount * TOKEN_PRICE);

        // El 33% que va para el vendedor de los tokens, se envian directamente a la billetera del vendedor.
        // Esto se hace en la funcion sell_able_from_list

        // Transferimos 33% para el Admin
        BUSD.transfer(communityWallet, ((_amount * TOKEN_PRICE) / 3));

        // Transferimos 33% para Able, para que lo otorgue en el regalo diario de Able.
        BUSD.transfer(address(ABLE), ((_amount * TOKEN_PRICE) / 3));

        // Transferimos los TOKEN al usuario
        TOKEN.transfer(msg.sender, _amount);

        // Buscamos los vendedores
        uint256 nfts_to_remove_sell;
        uint256 nfts_to_remove_driven;

        (nfts_to_remove_sell, nfts_to_remove_driven) = find_sellers(
            _amount,
            msg.sender
        );

        // Eliminamos de la lista, los vendedores que vendieron el total de su capital.
        for (uint256 i = 0; i < nfts_to_remove_sell; i++) {
            remove_first_nft_from_sell_list();
        }

        for (uint256 i = 0; i < nfts_to_remove_driven; i++) {
            remove_first_nft_from_driven_list();
        }

        // Aumentamos el BDD de esta billetera en ABLE
        if (incrementBDD)
            ABLE.incrementDonationBalance(_amount * TOKEN_PRICE, msg.sender);

        // Aumentamos la cantidad de tokens vendidos.
        TOTAL_TOKENS_SOLD += _amount;
        tokens_sold_by_cycle[ABLE.cycle()] += _amount;
    }

    function quit_sell(uint256 tokenID) public {
        require(is_selling(tokenID));
        require(SinergyContract.ownerOf(tokenID) == msg.sender);
        require(selling_amount_of[tokenID] > 0);
        require(total_selling_amount >= selling_amount_of[tokenID]);
        require(TOKEN.transfer(msg.sender, selling_amount_of[tokenID]));

        // Descontamos el monto que se saca de la venta
        total_selling_amount -= selling_amount_of[tokenID];
        selling_amount_of[tokenID] = 0;

        // Sacamos al NFT de la Lista de Venta TOKEN
        if (is_in_sell_list[tokenID]) {
            remove_nft_from_sell_list(get_index_of_nft_from_sell_list(tokenID));
        } else {
            remove_nft_from_driven_list(
                get_index_of_nft_from_driven_list(tokenID)
            );
        }
    }

    // Check Methods
    function check_sell_list() public {
        // Chequeamos si algun NFT de la Lista de Venta de Able esta descalificado.
        for (uint256 i = 0; i < sell_list.length; i++) {
            uint256 nft_id = sell_list[i];
            if (!SinergyContract.nft_was_qualified(nft_id)) {
                // Traemos todos los NFTs que habia detras una posicion mas adelante
                for (uint256 j = i; j < sell_list.length - 1; j++) {
                    sell_list[j] = sell_list[j + 1];
                }

                // Posicionamos al NFT sancionado en el ultimo lugar de la cola
                sell_list[sell_list.length - 1] = nft_id;

                emit BackToQueue(nft_id, i, sell_list.length - 1);
            }
        }
    }

    function check_driven_list() public {
        // Chequeamos si algun NFT de la Lista de Venta de Able esta descalificado.
        for (uint256 i = 0; i < driven_list.length; i++) {
            uint256 nft_id = driven_list[i];
            if (!SinergyContract.nft_was_qualified(nft_id)) {
                // Traemos todos los NFTs que habia detras una posicion mas adelante
                for (uint256 j = i; j < driven_list.length - 1; j++) {
                    driven_list[j] = sell_list[j + 1];
                }

                // Posicionamos al NFT sancionado en el ultimo lugar de la cola
                driven_list[driven_list.length - 1] = nft_id;

                emit BackToQueue(nft_id, i, driven_list.length - 1);
            }
        }
    }

    // Get Methods
    function get_sell_list_length() public view returns (uint256) {
        return sell_list.length;
    }

    function get_driven_list_length() public view returns (uint256) {
        return driven_list.length;
    }

    // Communication
    function try_to_swap(uint256 _tokenID) public {
        require(
            msg.sender == address(SinergyContract),
            "Only SinergyContract can call to this function."
        );

        if (
            is_selling(_tokenID) &&
            is_in_sell_list[_tokenID] &&
            (get_index_of_nft_from_sell_list(_tokenID) > driven_list.length)
        ) {
            remove_nft_from_sell_list(
                get_index_of_nft_from_sell_list(_tokenID)
            );
            set_nft_to_driven_list(_tokenID);

            emit SwapList(_tokenID);
        }
    }

    function set_sinergy(address _sinergyContract) public {
        require(
            msg.sender == dev_wallet,
            "You are not qualified to call this function."
        );
        SinergyContract = Sinergy(_sinergyContract);
    }

    function set_limit_post_by_cycle(uint256 new_limit) public {
        require(
            msg.sender == communityWallet || msg.sender == dev_wallet,
            "You are not qualified to call this function."
        );
        LIMIT_POST_BY_CYCLE = new_limit;
    }

    function set_values_of_sale(
        uint256 max_amount,
        uint256 min_amount,
        uint256 price
    ) public {
        /*
            Ninguno de los parametros tienen que estar en WEI.
            Tienen que estar directamente en Ether.
        */
        require(
            msg.sender == dev_wallet || msg.sender == communityWallet,
            "You are not qualified to call this function"
        );

        MAX_AMOUNT_SELL_TOKEN = max_amount * 1 ether;
        MIN_AMOUNT_SELL_TOKEN = min_amount * 1 ether;
        TOKEN_PRICE = price;
    }

    // Helpers
    function is_selling(uint256 _tokenID) public view returns (bool) {
        return is_in_sell_list[_tokenID] || is_in_driven_list[_tokenID];
    }

    // Sell Helpers
    function is_sell_turn() public view returns (bool) {
        return (turn == 2);
    }

    function sell_list_is_empty() public view returns (bool) {
        return sell_list.length == 0;
    }

    function can_use_sell() public view returns (bool) {
        return (!sell_list_is_empty() &&
            (is_sell_turn() || driven_list_is_empty()));
    }

    // Driven Helpers
    function can_be_in_driven_list(address wallet) public view returns (bool) {
        return
            ABLE.winSaverReward(wallet) &&
            ABLE.winsSaverRewardOf(wallet) > turns_in_driven_list_of[wallet];
    }

    function is_driven_turn() public view returns (bool) {
        return turn == 0 || turn == 1;
    }

    function driven_list_is_empty() public view returns (bool) {
        return driven_list.length == 0;
    }

    function can_use_driven() public view returns (bool) {
        return (!driven_list_is_empty() &&
            (is_driven_turn() || sell_list_is_empty()));
    }

    // Private Methods
    function set_nft_to_sell_list(uint256 _tokenID) private {
        sell_list.push(_tokenID);
        is_in_sell_list[_tokenID] = true;

        emit SellList(_tokenID, true, false);
    }

    function set_nft_to_driven_list(uint256 _tokenID) private {
        driven_list.push(_tokenID);
        is_in_driven_list[_tokenID] = true;

        emit SellList(_tokenID, true, true);
    }

    function remove_first_nft_from_sell_list() private {
        require(sell_list.length > 0);

        uint256 nft_id = sell_list[0];

        for (uint256 i = 0; i < sell_list.length - 1; i++) {
            sell_list[i] = sell_list[i + 1];
        }

        sell_list.pop();

        is_in_sell_list[nft_id] = false;

        emit SellList(nft_id, false, false);
    }

    function remove_first_nft_from_driven_list() private {
        require(driven_list.length > 0);

        uint256 nft_id = driven_list[0];

        for (uint256 i = 0; i < driven_list.length - 1; i++) {
            driven_list[i] = driven_list[i + 1];
        }

        driven_list.pop();

        is_in_driven_list[nft_id] = false;

        emit SellList(nft_id, false, true);
    }

    function remove_nft_from_sell_list(uint256 idx) private {
        require(sell_list.length > idx);

        uint256 nft_id = sell_list[idx];

        for (uint256 i = idx; i < sell_list.length - 1; i++) {
            sell_list[i] = sell_list[i + 1];
        }

        sell_list.pop();

        is_in_sell_list[nft_id] = false;

        emit SellList(nft_id, false, false);
    }

    function remove_nft_from_driven_list(uint256 idx) private {
        require(driven_list.length > idx);

        uint256 nft_id = driven_list[idx];

        for (uint256 i = idx; i < driven_list.length - 1; i++) {
            driven_list[i] = driven_list[i + 1];
        }

        driven_list.pop();

        is_in_driven_list[nft_id] = false;

        emit SellList(nft_id, false, true);
    }

    function can_sell(address wallet) private returns (bool) {
        if (block.timestamp > timestamp_last_post_sell[wallet]) {
            post_count_of[wallet] = 0;
            return true;
        }

        if (post_count_of[wallet] < LIMIT_POST_BY_CYCLE) {
            post_count_of[wallet]++;
            return true;
        }

        return false;
    }

    function get_index_of_nft_from_sell_list(
        uint256 tokenID
    ) private view returns (uint256) {
        for (uint256 i = 0; i < sell_list.length; i++) {
            if (sell_list[i] == tokenID) {
                return i;
            }
        }

        return sell_list.length + 1;
    }

    function get_index_of_nft_from_driven_list(
        uint256 tokenID
    ) private view returns (uint256) {
        for (uint256 i = 0; i < driven_list.length; i++) {
            if (driven_list[i] == tokenID) {
                return i;
            }
        }

        return driven_list.length + 1;
    }

    function sell_able_from_list(
        uint256 _amount,
        uint256 _tokenID,
        address buyer
    ) private {
        address owner = SinergyContract.ownerOf(_tokenID);

        selling_amount_of[_tokenID] -= _amount;
        total_selling_amount -= _amount;

        // 33% van directo al usuario
        BUSD.transfer(owner, ((_amount * TOKEN_PRICE) / 3));
        amount_sold_of[owner] += ((_amount * TOKEN_PRICE) / 3);

        emit SellToken(_tokenID, buyer, owner, _amount);
    }

    // Turn Helper
    function increment_turn() private {
        if (turn == 2) {
            turn = 0;
        } else {
            turn++;
        }
    }

    function find_sellers(
        uint256 _amount,
        address buyer
    ) private returns (uint256, uint256) {
        bool sell_all = false;
        uint256 nft_id;

        uint256 idx_sell = 0;
        uint256 nfts_to_remove_sell;

        uint256 idx_driven = 0;
        uint256 nfts_to_remove_driven;

        while (!sell_all) {
            // Driven List
            while (
                can_use_driven() && idx_driven < driven_list.length && !sell_all
            ) {
                nft_id = driven_list[idx_driven];

                if (_amount <= selling_amount_of[nft_id]) {
                    // Este NFT me da lo que necesito.
                    if (_amount == selling_amount_of[nft_id]) {
                        nfts_to_remove_driven++;
                    }

                    sell_able_from_list(_amount, nft_id, buyer);
                    sell_all = true;
                } else {
                    // Este NFT me ayuda a alcanzar lo que necesito. No me es suficiente lo que me da.
                    _amount -= selling_amount_of[nft_id];
                    sell_able_from_list(
                        selling_amount_of[nft_id],
                        nft_id,
                        buyer
                    );
                    nfts_to_remove_driven++;
                }

                idx_driven++;
                increment_turn();
            }

            // Sell List
            while (can_use_sell() && idx_sell < sell_list.length && !sell_all) {
                nft_id = sell_list[idx_sell];

                if (_amount <= selling_amount_of[nft_id]) {
                    // Este NFT me da lo que necesito.
                    if (_amount == selling_amount_of[nft_id]) {
                        nfts_to_remove_sell++;
                    }

                    sell_able_from_list(_amount, nft_id, buyer);
                    sell_all = true;
                } else {
                    // Este NFT me ayuda a alcanzar lo que necesito. No me es suficiente lo que me da.
                    _amount -= selling_amount_of[nft_id];
                    sell_able_from_list(
                        selling_amount_of[nft_id],
                        nft_id,
                        buyer
                    );
                    nfts_to_remove_sell++;
                }

                idx_sell++;
                increment_turn();
            }
        }

        return (nfts_to_remove_sell, nfts_to_remove_driven);
    }
}

contract Reward {
    // Contracts
    ERC20 public ABLE = ERC20(0x68627b19b01C497749328e160e17a168D7719956);
    ERC20 public TOKEN = ERC20(0x68627b19b01C497749328e160e17a168D7719956);
    SinergySale public ABLE_SALE =
        SinergySale(0xD42058180A985DEe1b52aEAEa5573D069D87Dc94);
    Sinergy public SinergyContract =
        Sinergy(0x508c132EE7cBb4A666E661634F85B59158eaDB4B);

    // Wallets
    address public developmentWallet =
        0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;

    // Attributes
    uint256 public TIME = 6 minutes;
    uint256 public reward_id;
    uint256 public AMOUNT_USERS_NEED_TO_CLAIM = 3;
    mapping(uint256 => uint256) public reward;
    mapping(uint256 => uint256) public reward_claimed;
    mapping(address => uint256) public timestamp_to_claim_reward;

    event RewardClaimed(uint256 amount, address indexed wallet);

    function set_reward(uint256 amount) public {
        require(can_call(msg.sender));
        reward[reward_id] += amount;
    }

    function claim_reward(bool passive) public {
        require(
            can_claim(msg.sender, passive),
            "You are not qualified to claim this reward."
        );
        uint256 amount = view_amount_to_claim(msg.sender, passive);

        // Transferimos los tokens correspondientes
        TOKEN.transfer(msg.sender, amount);

        set_reward_claimed(msg.sender, amount);

        emit RewardClaimed(amount, msg.sender);
    }

    function set_reward_claimed(address wallet, uint256 amount) private {
        reward_claimed[reward_id - 1] += amount;
        timestamp_to_claim_reward[wallet] = block.timestamp + TIME;
    }

    function view_amount_to_claim(
        address wallet,
        bool passive
    ) public view returns (uint256) {
        if (reward_id == 0) return 0;
        if (block.timestamp <= timestamp_to_claim_reward[wallet]) return 0;

        uint256 user_amount = get_user_amount(wallet, passive);
        uint256 total_amount = get_total_amount(passive);

        if (user_amount == 0) return 0;
        if (total_amount < user_amount) return 0;
        if (user_amount > 9) user_amount = 9;

        uint256 amount_to_claim = (user_amount * reward[reward_id - 1]) /
            total_amount;

        if (
            amount_to_claim >
            (reward[reward_id - 1] - reward_claimed[reward_id - 1])
        ) {
            return (reward[reward_id - 1] - reward_claimed[reward_id - 1]);
        }

        return amount_to_claim;
    }

    function update() public {
        require(can_call(msg.sender));
        reward_id++;
        if (reward[reward_id - 1] > reward_claimed[reward_id - 1]) {
            reward[reward_id] += (reward[reward_id - 1] -
                reward_claimed[reward_id - 1]);
        }
    }

    function can_claim(
        address wallet,
        bool passive
    ) public view returns (bool) {
        if (passive) {
            return (reward_id > 0 &&
                block.timestamp > timestamp_to_claim_reward[wallet] &&
                ABLE.canReclaim(wallet));
        }

        return (reward_id > 0 &&
            block.timestamp > timestamp_to_claim_reward[wallet] &&
            ABLE.canReclaim(wallet) &&
            ABLE.totalWinsSaverReward() >= AMOUNT_USERS_NEED_TO_CLAIM &&
            ABLE.winsSaverRewardOf(wallet) > 0);
    }

    function set_contracts(
        ERC20 _able,
        ERC20 _token,
        SinergySale _sinergySale,
        Sinergy _sinergyContract
    ) public {
        require(
            msg.sender == developmentWallet,
            "You are not qualified to call this function"
        );
        ABLE = _able;
        TOKEN = _token;
        ABLE_SALE = _sinergySale;
        SinergyContract = _sinergyContract;
    }

    // Getters
    function get_amount_raised() public view returns (uint256) {
        if (reward_id == 0) return 0;
        return reward[reward_id - 1];
    }

    function get_amount_claimed() public view returns (uint256) {
        if (reward_id == 0) return 0;
        return reward_claimed[reward_id - 1];
    }

    function can_call(address wallet) private view returns (bool) {
        return
            wallet == address(ABLE) ||
            wallet == address(ABLE_SALE) ||
            wallet == address(SinergyContract) ||
            wallet == developmentWallet;
    }

    function get_user_amount(
        address wallet,
        bool passive
    ) private view returns (uint256) {
        if (passive) {
            return SinergyContract.balanceOf(wallet);
        }

        return ABLE.winsSaverRewardOf(wallet);
    }

    function get_total_amount(bool passive) private view returns (uint256) {
        if (passive) {
            return SinergyContract.nfts_qualified();
        }

        return ABLE.totalWinsSaverReward();
    }
}

contract Migration {
    // Constants
    uint256 public constant AMOUNT_LIMIT_TO_MIGRATE = 21;

    // Contracts
    SinergyMigration ContractMigration =
        SinergyMigration(0xEa063b5A744616a161272a013a626A1cBD80Ee1B);
    Sinergy Contract = Sinergy(0x508c132EE7cBb4A666E661634F85B59158eaDB4B);

    // ERC20
    ERC20 public ABLE = ERC20(0x68627b19b01C497749328e160e17a168D7719956);

    // Addresses
    address public communityWallet = 0xc8895f6f85D870589C42fd6d531c855bddD27B0f;
    address public constant developmentWallet =
        0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;

    // Migration
    mapping(address => bool) public isRecover;
    mapping(uint256 => bool) public nftRecover;

    mapping(uint256 => bool) public first_level_references_recover;
    mapping(uint256 => uint256) public first_level_references_recover_amount;

    mapping(uint256 => bool) public second_level_references_recover;
    mapping(uint256 => uint256) public second_level_references_recover_amount;

    mapping(uint256 => bool) public third_level_references_recover;
    mapping(uint256 => uint256) public third_level_references_recover_amount;

    mapping(uint256 => bool) public four_level_references_recover;
    mapping(uint256 => uint256) public four_level_references_recover_amount;

    mapping(uint256 => bool) public five_level_references_recover;
    mapping(uint256 => uint256) public five_level_references_recover_amount;

    mapping(uint256 => bool) public six_level_references_recover;
    mapping(uint256 => uint256) public six_level_references_recover_amount;

    mapping(uint256 => bool) public seven_level_references_recover;
    mapping(uint256 => uint256) public seven_level_references_recover_amount;

    mapping(uint256 => bool) public eight_level_references_recover;
    mapping(uint256 => uint256) public eight_level_references_recover_amount;

    mapping(uint256 => bool) public nine_level_references_recover;
    mapping(uint256 => uint256) public nine_level_references_recover_amount;

    mapping(address => uint256) public nfts_migrated;
    uint256 public starting_nft_id;
    uint256[] public recovered_nfts;
    uint256 public recovered_nfts_amount;

    constructor() {
        isRecover[developmentWallet] = true;
    }

    // Main recover
    function migrate() public {
        if (msg.sender == communityWallet && !isRecover[communityWallet]) {
            Contract.create_genesis_nfts();
            isRecover[communityWallet] = true;
            handle_recover_nfts_amount_for_admin();
            return;
        }

        if (!isRecover[msg.sender]) {
            uint256 affiliate_rewards;
            uint256 amount = ContractMigration.balanceOf(msg.sender);
            uint256 migrated;
            uint256 nftID;

            while (
                migrated < AMOUNT_LIMIT_TO_MIGRATE &&
                nfts_migrated[msg.sender] < amount
            ) {
                nftID = ContractMigration.get_my_nfts(
                    msg.sender,
                    nfts_migrated[msg.sender]
                );
                recovered_nfts.push(nftID);

                Contract.handleRecover(msg.sender, nftID);
                nftRecover[nftID] = true;

                recovered_nfts_amount++;
                affiliate_rewards += ContractMigration.get_nft_balance_to_claim(
                    nftID
                );

                nfts_migrated[msg.sender]++;
                migrated++;
            }

            if (nfts_migrated[msg.sender] == amount) {
                ABLE.transfer(msg.sender, affiliate_rewards);
                isRecover[msg.sender] = true;
            }
        }
    }

    // Recover by level
    function recoverFirstLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !first_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_first_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            first_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverFirstLevel(
                nftID,
                first_level_references_recover_amount[nftID]
            );
            migrated++;
            first_level_references_recover_amount[nftID]++;
        }

        if (first_level_references_recover_amount[nftID] == amount) {
            first_level_references_recover[nftID] = true;
        }
    }

    function recoverSecondLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !second_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_second_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            second_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverSecondLevel(
                nftID,
                second_level_references_recover_amount[nftID]
            );
            migrated++;
            second_level_references_recover_amount[nftID]++;
        }

        if (second_level_references_recover_amount[nftID] == amount) {
            second_level_references_recover[nftID] = true;
        }
    }

    function recoverThirdLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !third_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_third_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            third_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverThirdLevel(
                nftID,
                third_level_references_recover_amount[nftID]
            );
            migrated++;
            third_level_references_recover_amount[nftID]++;
        }

        if (third_level_references_recover_amount[nftID] == amount) {
            third_level_references_recover[nftID] = true;
        }
    }

    function recoverFourLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !four_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_four_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            four_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverFourLevel(
                nftID,
                four_level_references_recover_amount[nftID]
            );
            migrated++;
            four_level_references_recover_amount[nftID]++;
        }

        if (four_level_references_recover_amount[nftID] == amount) {
            four_level_references_recover[nftID] = true;
        }
    }

    function recoverFiveLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !five_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_five_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            five_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverFiveLevel(
                nftID,
                five_level_references_recover_amount[nftID]
            );
            migrated++;
            five_level_references_recover_amount[nftID]++;
        }

        if (five_level_references_recover_amount[nftID] == amount) {
            five_level_references_recover[nftID] = true;
        }
    }

    function recoverSixLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !six_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_six_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            six_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverSixLevel(
                nftID,
                six_level_references_recover_amount[nftID]
            );
            migrated++;
            six_level_references_recover_amount[nftID]++;
        }

        if (six_level_references_recover_amount[nftID] == amount) {
            six_level_references_recover[nftID] = true;
        }
    }

    function recoverSevenLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !seven_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_seven_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            seven_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverSevenLevel(
                nftID,
                seven_level_references_recover_amount[nftID]
            );
            migrated++;
            seven_level_references_recover_amount[nftID]++;
        }

        if (seven_level_references_recover_amount[nftID] == amount) {
            seven_level_references_recover[nftID] = true;
        }
    }

    function recoverEightLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !eight_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_eight_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            eight_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverEightLevel(
                nftID,
                eight_level_references_recover_amount[nftID]
            );
            migrated++;
            eight_level_references_recover_amount[nftID]++;
        }

        if (eight_level_references_recover_amount[nftID] == amount) {
            eight_level_references_recover[nftID] = true;
        }
    }

    function recoverNineLevelReferences(uint256 nftID) public {
        require(
            msg.sender == Contract.ownerOf(nftID) &&
                !nine_level_references_recover[nftID]
        );

        uint256 migrated;
        uint256 amount = ContractMigration.get_nine_level_amount_reference(
            nftID
        );
        while (
            migrated < AMOUNT_LIMIT_TO_MIGRATE &&
            nine_level_references_recover_amount[nftID] < amount
        ) {
            Contract.handlerRecoverNineLevel(
                nftID,
                nine_level_references_recover_amount[nftID]
            );
            migrated++;
            nine_level_references_recover_amount[nftID]++;
        }

        if (nine_level_references_recover_amount[nftID] == amount) {
            nine_level_references_recover[nftID] = true;
        }
    }

    // Helpers
    function handle_recover_nfts_amount_for_admin() private {
        for (uint8 i = 0; i < 9; i++) {
            recovered_nfts.push(i);
            recovered_nfts_amount++;
        }
    }

    // Set Contracts
    function set_sinergy(Sinergy _sinergyAddress) public {
        if (msg.sender != developmentWallet) return;
        Contract = Sinergy(_sinergyAddress);
    }

    function set_able(ERC20 _able) public {
        if (msg.sender != developmentWallet) return;
        ABLE = ERC20(_able);
    }
}

// This is the main contract here!
contract Sinergy is ERC721, ERC721URIStorage, Ownable {
    // Constants
    uint256 public constant PRICE = 36 ether;
    uint256 public constant ABLE_PRICE = 12 ether;
    uint256 public constant REWARD = 3 ether;
    uint256 public constant TO_DEVELOPMENT = 3 ether;

    // NFT GENESIS
    string constant NFT_GENESIS_NAME = "GENESIS";
    string constant NFT_GENESIS_INSCRIPTION = "GENESIS INSCRIPTION";
    string constant NFT_GENESIS_VALUE_PROPOSAL = "GENESIS VALUE PROPOSAL";
    string constant NFT_GENESIS_IMAGE_URL =
        "https://res.cloudinary.com/saver-community/image/upload/v1666380501/jvjbls4lg5mtxsxhlhnf.png";

    // Migration
    SinergyMigration ContractMigration =
        SinergyMigration(0xEa063b5A744616a161272a013a626A1cBD80Ee1B);

    Migration public MigrationContract =
        Migration(0xfd26B8BE868C0E16A5a54E8D586B0C6D7d6892fA);

    // ERC20's
    ERC20 public ABLE = ERC20(0x0b85cCA1814eE40C6E83E3591F3819eC7e87d0A5);
    ERC20 public BUSD = ERC20(0x765277EebeCA2e31912C9946eAe1021199B39C61);

    // Able Sale
    SinergySale public ABLE_SALE =
        SinergySale(0x7fa46675165F0d0Ab1A3bd3FD96AA3eD59167B52);

    // Passive Rewards
    Reward public BUSD_PassiveReward =
        Reward(0x4F19668690b3501fa2404039436d4f1C14079dB8);
    Reward public ABLE_PassiveReward =
        Reward(0x72e29bC0cF7E6f2A3FC99890069E857b736F6dE9);

    // Constancy Rewards (usa el ID de las pasivas)
    Reward public BUSD_ConstancyReward =
        Reward(0x2B06dD06Cf7cdAB0f8cC39a6F79FD88b20cb2C5D);
    Reward public ABLE_ConstancyReward =
        Reward(0xc32AfBC61e4A2Be096cBe27Fa1072EA7f25Aa79d);

    // Address
    address public communityWallet = 0xc8895f6f85D870589C42fd6d531c855bddD27B0f;
    address public constant developmentWallet =
        0x9060723c22dE586c2fA5eFa07A7743F6f4a935f5;

    uint256 public oneDay = 1 days;
    uint256 public timeToNextReward;

    // Counters
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    uint256 public starting_nft_id;
    uint256 initial_tokenID = 1159;

    // Constructor
    constructor() ERC721("Offer Sinergy", "Sinergy") {
        while (_tokenIds.current() < initial_tokenID) {
            _tokenIds.increment();
        }

        // Mint NFT
        uint256 tokenID = _tokenIds.current();
        _tokenIds.increment();
        _safeMint(developmentWallet, tokenID);
        get_nft_name[tokenID] = NFT_GENESIS_NAME;
        get_nft_inscription[tokenID] = NFT_GENESIS_INSCRIPTION;
        get_nft_value_proposal[tokenID] = NFT_GENESIS_VALUE_PROPOSAL;
        get_nft_image_url[tokenID] = NFT_GENESIS_IMAGE_URL;
        get_nft_timestamp_created[tokenID] = block.timestamp;
        favourite_nft[developmentWallet] = tokenID;

        _setTokenURI(
            tokenID,
            "ipfs://QmRi1DvgDu6zAJwpbURGNBBQTM82ZCNZAyTkEArbKZKm1U/273.json"
        );

        get_my_nfts[developmentWallet].push(tokenID);

        timeToNextReward = block.timestamp + oneDay;
        starting_nft_id = initial_tokenID;

        total_holders++;

        is_holder[developmentWallet] = true;
    }

    // NFT's
    uint256 public nfts_qualified;
    mapping(address => bool) public is_qualified;
    mapping(uint256 => string) public get_nft_name;
    mapping(uint256 => string) public get_nft_inscription;
    mapping(uint256 => string) public get_nft_value_proposal;
    mapping(uint256 => uint256) public get_nft_timestamp_created;
    mapping(uint256 => string) public get_nft_image_url;

    // References
    // Esto sabemos que va (Cantidad de NFTs que estan conectados conmigo en el NIVEL x)
    mapping(uint256 => uint256) public get_first_level_amount_reference;
    mapping(uint256 => uint256) public get_second_level_amount_reference;
    mapping(uint256 => uint256) public get_third_level_amount_reference;
    mapping(uint256 => uint256) public get_four_level_amount_reference;
    mapping(uint256 => uint256) public get_five_level_amount_reference;
    mapping(uint256 => uint256) public get_six_level_amount_reference;
    mapping(uint256 => uint256) public get_seven_level_amount_reference;
    mapping(uint256 => uint256) public get_eight_level_amount_reference;
    mapping(uint256 => uint256) public get_nine_level_amount_reference;

    mapping(uint256 => uint256) public get_total_amount_references; // Cantidad de NFTs que estan conectados conmigo en total.

    // Esto puede fallar (NFT ID de cada uno que esta conectado con nosotros en el NIVEL x)
    mapping(uint256 => uint256[]) public get_first_level_references;
    mapping(uint256 => uint256[]) public get_second_level_references;
    mapping(uint256 => uint256[]) public get_third_level_references;
    mapping(uint256 => uint256[]) public get_four_level_references;
    mapping(uint256 => uint256[]) public get_five_level_references;
    mapping(uint256 => uint256[]) public get_six_level_references;
    mapping(uint256 => uint256[]) public get_seven_level_references;
    mapping(uint256 => uint256[]) public get_eight_level_references;
    mapping(uint256 => uint256[]) public get_nine_level_references;

    // NFT al que me conecte
    mapping(uint256 => uint256) public get_nft_reference;

    // Rewards
    mapping(uint256 => uint256) public nft_affiliate_rewards_earned;

    // Resources
    uint256 public total_raided_for_admin;

    // Stadistics
    uint256 public total_stablecoin_distributed;
    mapping(address => uint256) public total_stablecoin_earned;
    mapping(address => uint256) public total_lost_income;
    mapping(address => uint256) public actual_lost_income;
    mapping(uint256 => uint256) public nfts_created_by_cycle;

    // Holders
    mapping(address => bool) public is_holder;
    uint256 public total_holders;

    // Auxs
    mapping(address => uint256) public amount_nfts_considered;

    // Events
    event Mint(
        uint256 id,
        uint256 date,
        string indexed name,
        string indexed valueProposal,
        address indexed wallet
    );

    event AffiliateRewardEvent(
        uint256 tokenID,
        uint256 amount,
        address indexed wallet,
        uint256 indexed date
    );

    event ChangeFavourite(
        address indexed wallet,
        uint256 previousFavourite,
        uint256 actualFavourite
    );

    // Public Functions
    // Migration

    function set_migration_contract(Migration _migrationContract) public {
        if (msg.sender != developmentWallet) return;
        MigrationContract = _migrationContract;
    }

    function handleRecover(address wallet, uint256 tokenId) public {
        if (msg.sender != address(MigrationContract)) return;

        recoverNFT(tokenId);
        get_my_nfts[wallet].push(tokenId);
        _safeMint(wallet, tokenId);

        if (favourite_nft[wallet] == 0) {
            favourite_nft[wallet] = tokenId;
        }
    }

    function recoverNFT(uint256 nftID) private {
        // NFT Basic Info
        get_nft_name[nftID] = ContractMigration.get_nft_name(nftID);
        get_nft_inscription[nftID] = ContractMigration.get_nft_inscription(
            nftID
        );
        get_nft_value_proposal[nftID] = ContractMigration
            .get_nft_value_proposal(nftID);
        get_nft_timestamp_created[nftID] = ContractMigration
            .get_nft_timestamp_created(nftID);
        get_nft_image_url[nftID] = ContractMigration.get_nft_image_url(nftID);
        get_nft_reference[nftID] = ContractMigration.get_nft_reference(nftID);

        // References
        get_first_level_amount_reference[nftID] = ContractMigration
            .get_first_level_amount_reference(nftID);
        get_second_level_amount_reference[nftID] = ContractMigration
            .get_second_level_amount_reference(nftID);
        get_third_level_amount_reference[nftID] = ContractMigration
            .get_third_level_amount_reference(nftID);
        get_four_level_amount_reference[nftID] = ContractMigration
            .get_four_level_amount_reference(nftID);
        get_five_level_amount_reference[nftID] = ContractMigration
            .get_five_level_amount_reference(nftID);
        get_six_level_amount_reference[nftID] = ContractMigration
            .get_six_level_amount_reference(nftID);
        get_seven_level_amount_reference[nftID] = ContractMigration
            .get_seven_level_amount_reference(nftID);
        get_eight_level_amount_reference[nftID] = ContractMigration
            .get_eight_level_amount_reference(nftID);
        get_nine_level_amount_reference[nftID] = ContractMigration
            .get_nine_level_amount_reference(nftID);

        get_total_amount_references[nftID] = ContractMigration
            .get_total_amount_references(nftID);
    }

    function handlerRecoverFirstLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_first_level_references[tokenId].push(
            ContractMigration.get_first_level_references(tokenId, index)
        );
    }

    function handlerRecoverSecondLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_second_level_references[tokenId].push(
            ContractMigration.get_second_level_references(tokenId, index)
        );
    }

    function handlerRecoverThirdLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_third_level_references[tokenId].push(
            ContractMigration.get_third_level_references(tokenId, index)
        );
    }

    function handlerRecoverFourLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_four_level_references[tokenId].push(
            ContractMigration.get_four_level_references(tokenId, index)
        );
    }

    function handlerRecoverFiveLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_five_level_references[tokenId].push(
            ContractMigration.get_five_level_references(tokenId, index)
        );
    }

    function handlerRecoverSixLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_six_level_references[tokenId].push(
            ContractMigration.get_six_level_references(tokenId, index)
        );
    }

    function handlerRecoverSevenLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_seven_level_references[tokenId].push(
            ContractMigration.get_seven_level_references(tokenId, index)
        );
    }

    function handlerRecoverEightLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_eight_level_references[tokenId].push(
            ContractMigration.get_eight_level_references(tokenId, index)
        );
    }

    function handlerRecoverNineLevel(uint256 tokenId, uint256 index) public {
        if (msg.sender != address(MigrationContract)) return;

        get_nine_level_references[tokenId].push(
            ContractMigration.get_nine_level_references(tokenId, index)
        );
    }

    // NFT
    function createNFT(
        string memory _name,
        string memory _inscription,
        string memory _valueProposal,
        string memory _uri,
        string memory _imageURL,
        uint256 _ref,
        uint256 _timestamp
    ) public {
        // Get Reference

        uint256 _reference = favourite_nft[ABLE.lastDonationFrom()];

        if (_ref != 0) {
            _reference = _ref;
        }

        if (_reference == 0) {
            _reference = 8;
        }

        require(_reference < _tokenIds.current());

        BUSD.transferFrom(msg.sender, address(this), PRICE);
        ABLE.transferFrom(msg.sender, address(this), ABLE_PRICE);

        // Transferimos 3 BUSD para el admin
        BUSD.transfer(communityWallet, TO_DEVELOPMENT);

        update_qualified_nfts(msg.sender);

        ABLE_SALE.try_to_swap(favourite_nft[msg.sender]);

        // Mint NFT
        uint256 tokenID = _tokenIds.current();
        _tokenIds.increment();
        _safeMint(msg.sender, tokenID);

        // Set URI
        _setTokenURI(tokenID, _uri);

        // Add information to the NFT
        get_nft_name[tokenID] = _name;
        get_nft_inscription[tokenID] = _inscription;
        get_nft_value_proposal[tokenID] = _valueProposal;
        get_nft_reference[tokenID] = _reference;

        get_nft_image_url[tokenID] = _imageURL;
        get_nft_timestamp_created[tokenID] = _timestamp;

        if (favourite_nft[msg.sender] == 0) {
            favourite_nft[msg.sender] = tokenID;
        }

        // uint256[] storage myNFTS = get_my_nfts[msg.sender];
        get_my_nfts[msg.sender].push(tokenID);
        // get_my_nfts[msg.sender] = myNFTS;

        // Increase the resources amount
        total_raided_for_admin += TO_DEVELOPMENT;

        // Increase Rewards
        ABLE_PassiveReward.set_reward(6 ether);
        ABLE.transfer(address(ABLE_PassiveReward), 6 ether);

        BUSD_PassiveReward.set_reward(3 ether);
        BUSD.transfer(address(BUSD_PassiveReward), 3 ether);

        ABLE_ConstancyReward.set_reward(6 ether);
        ABLE.transfer(address(ABLE_ConstancyReward), 6 ether);

        BUSD_ConstancyReward.set_reward(3 ether);
        BUSD.transfer(address(BUSD_ConstancyReward), 3 ether);

        // Distribute BUSD's in 9 generations
        distribute(tokenID, _reference, true);

        update(msg.sender);

        // Aumentamos la cantidad de NFTs creados en este ciclo
        nfts_created_by_cycle[ABLE.cycle()]++;

        // Holders
        if (!is_holder[msg.sender]) {
            is_holder[msg.sender] = true;
            total_holders++;
        }

        // Emit event
        emit Mint(tokenID, block.timestamp, _name, _valueProposal, msg.sender);
    }

    function modifyNFT(
        string memory _name,
        string memory _inscription,
        string memory _valueProposal,
        uint256 _tokenID
    ) public {
        require(msg.sender == ownerOf(_tokenID));

        BUSD.transferFrom(msg.sender, address(this), PRICE);
        ABLE.transferFrom(msg.sender, address(this), ABLE_PRICE);

        // Transferimos 3 BUSD para el admin
        BUSD.transfer(communityWallet, TO_DEVELOPMENT);

        // Modify the NFT
        get_nft_name[_tokenID] = _name;
        get_nft_inscription[_tokenID] = _inscription;
        get_nft_value_proposal[_tokenID] = _valueProposal;

        // Increase the resources amount
        total_raided_for_admin += TO_DEVELOPMENT;

        // Increase Rewards
        BUSD_PassiveReward.set_reward(3 ether);
        BUSD.transfer(address(BUSD_PassiveReward), 3 ether);

        ABLE_PassiveReward.set_reward(6 ether);
        ABLE.transfer(address(ABLE_PassiveReward), 6 ether);

        ABLE_ConstancyReward.set_reward(6 ether);
        ABLE.transfer(address(ABLE_ConstancyReward), 6 ether);

        BUSD_ConstancyReward.set_reward(3 ether);
        BUSD.transfer(address(ABLE_ConstancyReward), 3 ether);

        // Distribute BUSD in 9 generations
        distribute(_tokenID, get_nft_reference[_tokenID], false);

        update(msg.sender);
    }

    // Read functions
    function getAmountOfNftMinted() public view returns (uint256) {
        return _tokenIds.current();
    }

    // Set Functions
    function setAbleAddress(address _ableAddress) public {
        require(msg.sender == developmentWallet);

        ABLE = ERC20(_ableAddress);
    }

    function setRewards(
        Reward busd_passive,
        Reward busd_constancy,
        Reward able_passive,
        Reward able_constancy
    ) public {
        require(msg.sender == developmentWallet);
        BUSD_PassiveReward = busd_passive;
        BUSD_ConstancyReward = busd_constancy;
        ABLE_PassiveReward = able_passive;
        ABLE_ConstancyReward = able_constancy;
    }

    function setFavouriteNFT(address wallet, uint256 id) public {
        require(id <= _tokenIds.current());
        require(msg.sender == ownerOf(id) || msg.sender == address(MigrationContract), "Wallet not qualified to setFavouriteNFT");

        uint256 previousFavourite = favourite_nft[wallet];
        favourite_nft[wallet] = id;

        emit ChangeFavourite(msg.sender, previousFavourite, id);
    }

    function changeCommunityWallet(address newAddress) public {
        require(msg.sender == communityWallet);

        communityWallet = newAddress;
    }

    // Booleans
    function nft_was_qualified(uint256 tokenID) public view returns (bool) {
        return
            ABLE.canReclaim(ownerOf(tokenID)) ||
            ABLE.qualifiedHistory(ownerOf(tokenID), ABLE.cycle() - 1);
    }

    // Update Functions
    function update_qualified_nfts(address wallet) private {
        if (is_qualified[wallet]) {
            nfts_qualified -= amount_nfts_considered[wallet];
            amount_nfts_considered[wallet] = 0;
            is_qualified[wallet] = false;
        }

        if (ABLE.canReclaim(wallet)) {
            nfts_qualified += balanceOf(wallet);
            amount_nfts_considered[wallet] = balanceOf(wallet);
            is_qualified[wallet] = true;
        }
    }

    function update_timestamp() private {
        if (block.timestamp > timeToNextReward) {
            BUSD_PassiveReward.update();
            ABLE_PassiveReward.update();

            BUSD_ConstancyReward.update();
            ABLE_ConstancyReward.update();

            timeToNextReward = block.timestamp + oneDay;
        }
    }

    function update(address wallet) public {
        ABLE.updateFromSinergy(wallet);

        update_timestamp();

        update_qualified_nfts(wallet);
    }

    function updateFromAble(address wallet) public {
        update_timestamp();
        update_qualified_nfts(wallet);
    }

    function getAbleBalance(address wallet) public view returns (uint256) {
        return ABLE.balanceOf(wallet);
    }

    // SaleToken Public Functions
    function set_able_sale(SinergySale ableSale) public {
        require(msg.sender == developmentWallet);
        ABLE_SALE = ableSale;
    }

    // Private Functions

    // Distribute 9 generations
    function distribute(
        uint256 tokenID,
        uint256 _reference,
        bool created
    ) private {
        address owner;
        uint256 i = 0;
        while (i < 9) {
            if (created) setReferences(i, tokenID, _reference);

            owner = ownerOf(_reference);

            total_stablecoin_earned[owner] += REWARD;
            nft_affiliate_rewards_earned[_reference] += REWARD;
            total_stablecoin_distributed += REWARD;
            BUSD.transfer(owner, REWARD);

            // Emit events
            emit AffiliateRewardEvent(
                _reference,
                REWARD,
                owner,
                block.timestamp
            );

            _reference = get_nft_reference[_reference];

            i++;
        }
    }

    function create_genesis_nfts() public {
        if (msg.sender != address(MigrationContract)) return;

        // Crear 8 NFTs para la billetera destinada a Desarrollo y Mantenimiento
        // Estos NFTs deben estar vinculados entre si
        uint256 affiliate_rewards;

        for (uint256 i = 0; i < 9; i++) {
            _safeMint(communityWallet, i);

            recoverNFT(i);

            affiliate_rewards += ContractMigration.get_nft_balance_to_claim(i);

            get_my_nfts[communityWallet].push(i);

            _setTokenURI(
                i,
                "ipfs://QmRi1DvgDu6zAJwpbURGNBBQTM82ZCNZAyTkEArbKZKm1U/0.json"
            );
        }
    }

    function setReferences(uint256 i, uint256 tokenID, uint256 ref) private {
        if (i == 0) {
            get_first_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_first_level_references[ref];
            get_first_level_references[ref].push(tokenID);
            // get_first_level_references[ref] = nftIDs;

            return;
        }

        if (i == 1) {
            get_second_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_second_level_references[ref];
            get_second_level_references[ref].push(tokenID);
            // get_second_level_references[ref] = nftIDs;

            return;
        }

        if (i == 2) {
            get_third_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_third_level_references[ref];
            get_third_level_references[ref].push(tokenID);
            // get_third_level_references[ref] = nftIDs;

            return;
        }

        if (i == 3) {
            get_four_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_four_level_references[ref];
            get_four_level_references[ref].push(tokenID);
            // get_four_level_references[ref] = nftIDs;

            return;
        }

        if (i == 4) {
            get_five_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_five_level_references[ref];
            get_five_level_references[ref].push(tokenID);
            // get_five_level_references[ref] = nftIDs;

            return;
        }

        if (i == 5) {
            get_six_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_six_level_references[ref];
            get_six_level_references[ref].push(tokenID);
            // get_six_level_references[ref] = nftIDs;

            return;
        }

        if (i == 6) {
            get_seven_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_seven_level_references[ref];
            get_seven_level_references[ref].push(tokenID);
            // get_seven_level_references[ref] = nftIDs;

            return;
        }

        if (i == 7) {
            get_eight_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_eight_level_references[ref];
            get_eight_level_references[ref].push(tokenID);
            // get_eight_level_references[ref] = nftIDs;

            return;
        }

        if (i == 8) {
            get_nine_level_amount_reference[ref]++;
            get_total_amount_references[ref]++;
            // uint256[] storage nftIDs = get_nine_level_references[ref];
            get_nine_level_references[ref].push(tokenID);
            // get_nine_level_references[ref] = nftIDs;

            return;
        }
    }

    // The following functions are overrides required by Solidity.

    function _burn(
        uint256 tokenId
    ) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(
        uint256 tokenId
    ) public view override(ERC721, ERC721URIStorage) returns (string memory) {
        return super.tokenURI(tokenId);
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":true,"internalType":"uint256","name":"date","type":"uint256"}],"name":"AffiliateRewardEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousFavourite","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"actualFavourite","type":"uint256"}],"name":"ChangeFavourite","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"date","type":"uint256"},{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"string","name":"valueProposal","type":"string"},{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"ABLE","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ABLE_ConstancyReward","outputs":[{"internalType":"contract Reward","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ABLE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ABLE_PassiveReward","outputs":[{"internalType":"contract Reward","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ABLE_SALE","outputs":[{"internalType":"contract SinergySale","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUSD","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUSD_ConstancyReward","outputs":[{"internalType":"contract Reward","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUSD_PassiveReward","outputs":[{"internalType":"contract Reward","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MigrationContract","outputs":[{"internalType":"contract Migration","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TO_DEVELOPMENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"actual_lost_income","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"amount_nfts_considered","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"changeCommunityWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"communityWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_inscription","type":"string"},{"internalType":"string","name":"_valueProposal","type":"string"},{"internalType":"string","name":"_uri","type":"string"},{"internalType":"string","name":"_imageURL","type":"string"},{"internalType":"uint256","name":"_ref","type":"uint256"},{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"createNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"create_genesis_nfts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"developmentWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"favourite_nft","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"getAbleBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAmountOfNftMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_eight_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_eight_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_first_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_first_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_five_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_five_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_four_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_four_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_my_nfts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nft_image_url","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nft_inscription","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nft_name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nft_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nft_timestamp_created","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nft_value_proposal","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nine_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_nine_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_second_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_second_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_seven_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_seven_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_six_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_six_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_third_level_amount_reference","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_third_level_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"get_total_amount_references","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"handleRecover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverEightLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverFirstLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverFiveLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverFourLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverNineLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverSecondLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverSevenLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverSixLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"handlerRecoverThirdLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"is_holder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"is_qualified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_inscription","type":"string"},{"internalType":"string","name":"_valueProposal","type":"string"},{"internalType":"uint256","name":"_tokenID","type":"uint256"}],"name":"modifyNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nft_affiliate_rewards_earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"nft_was_qualified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nfts_created_by_cycle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nfts_qualified","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oneDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ableAddress","type":"address"}],"name":"setAbleAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"setFavouriteNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Reward","name":"busd_passive","type":"address"},{"internalType":"contract Reward","name":"busd_constancy","type":"address"},{"internalType":"contract Reward","name":"able_passive","type":"address"},{"internalType":"contract Reward","name":"able_constancy","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract SinergySale","name":"ableSale","type":"address"}],"name":"set_able_sale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Migration","name":"_migrationContract","type":"address"}],"name":"set_migration_contract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"starting_nft_id","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeToNextReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"total_holders","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"total_lost_income","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"total_raided_for_admin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"total_stablecoin_distributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"total_stablecoin_earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"}],"name":"updateFromAble","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateFromAble","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600a80546001600160a01b031990811673ea063b5a744616a161272a013a626a1cbd80ee1b17909155600b8054821673fd26b8be868c0e16a5a54e8d586b0c6d7d6892fa179055600c80548216730b85cca1814ee40c6e83e3591f3819ec7e87d0a5179055600d8054821673765277eebeca2e31912c9946eae1021199b39c61179055600e80548216737fa46675165f0d0ab1a3bd3fd96aa3ed59167b52179055600f80548216734f19668690b3501fa2404039436d4f1c14079db81790556010805482167372e29bc0cf7e6f2a3fc99890069e857b736f6de9179055601180548216732b06dd06cf7cdab0f8cc39a6f79fd88b20cb2c5d17905560128054821673c32afbc61e4a2be096cbe27fa1072ea7f25aa79d1790556013805490911673c8895f6f85d870589c42fd6d531c855bddd27b0f179055620151806014556104876018553480156200015657600080fd5b50604080518082018252600d81526c4f666665722053696e6572677960981b60208083019182528351808501909452600784526653696e6572677960c81b908401528151919291620001ab91600091620007bd565b508051620001c1906001906020840190620007bd565b505050620001de620001d8620004e260201b60201c565b620004e6565b601854620001f860166200053860201b62002b121760201c565b10156200021c576200021660166200053c60201b62002b161760201c565b620001de565b60006200023560166200053860201b62002b121760201c565b90506200024e60166200053c60201b62002b161760201c565b6200026e739060723c22de586c2fa5efa07a7743f6f4a935f58262000545565b604080518082018252600781526647454e4553495360c81b60208083019182526000858152601b909152929092209051620002aa9290620007bd565b50604080518082018252601381527f47454e4553495320494e534352495054494f4e0000000000000000000000000060208083019182526000858152601c909152929092209051620002fd9290620007bd565b50604080518082018252601681527f47454e455349532056414c55452050524f504f53414c0000000000000000000060208083019182526000858152601d909152929092209051620003509290620007bd565b506040518060800160405280605c815260200162005997605c91396000828152601f602090815260409091208251620003909391929190910190620007bd565b506000818152601e60209081526040808320429055739060723c22de586c2fa5efa07a7743f6f4a935f5909252600781527ff0f65e204a552941be11f09a7255d57c9fb6370598c96860a72420b18c78f78b839055815160608101909252603e8083526200040b928492909190620059f3908301396200056b565b60066020527ea535364af8b72a27ad8fea04427a99c3496881b6eeecf55e51e8e1d0096a9380546001810182556000919091527f4ea4f0f529ea4326092b46e5231da2b02a7ce14afeead36ac08f50bb9aa671c10181905560145462000472904262000911565b601555601854601755603c80549060006200048d8362000969565b9091555050739060723c22de586c2fa5efa07a7743f6f4a935f560005250603b6020527fa68fd757b359b471585cc9d12d08d13ee4410790d3ea103994bd4a20c8cd506a805460ff191660011790556200099d565b3390565b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b5490565b80546001019055565b62000567828260405180602001604052806000815250620005a660201b60201c565b5050565b6200057682620005cb565b6200058057600080fd5b60008281526008602090815260409091208251620005a192840190620007bd565b505050565b620005b28383620005e8565b620005c1600084848462000693565b620005a157600080fd5b6000908152600260205260409020546001600160a01b0316151590565b6001600160a01b038216620005fc57600080fd5b6200060781620005cb565b156200061257600080fd5b6200061d81620005cb565b156200062857600080fd5b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000620006b4846001600160a01b0316620007ae60201b62002b1f1760201c565b15620007a257604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290620006ee90339089908890889060040162000896565b602060405180830381600087803b1580156200070957600080fd5b505af19250505080156200073c575060408051601f3d908101601f19168201909252620007399181019062000863565b60015b62000787573d8080156200076d576040519150601f19603f3d011682016040523d82523d6000602084013e62000772565b606091505b5080516200077f57600080fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050620007a6565b5060015b949350505050565b6001600160a01b03163b151590565b828054620007cb906200092c565b90600052602060002090601f016020900481019282620007ef57600085556200083a565b82601f106200080a57805160ff19168380011785556200083a565b828001600101855582156200083a579182015b828111156200083a5782518255916020019190600101906200081d565b50620008489291506200084c565b5090565b5b808211156200084857600081556001016200084d565b6000602082840312156200087657600080fd5b81516001600160e01b0319811681146200088f57600080fd5b9392505050565b600060018060a01b038087168352602081871681850152856040850152608060608501528451915081608085015260005b82811015620008e55785810182015185820160a001528101620008c7565b82811115620008f857600060a084870101525b5050601f01601f19169190910160a00195945050505050565b6000821982111562000927576200092762000987565b500190565b600181811c908216806200094157607f821691505b602082108114156200096357634e487b7160e01b600052602260045260246000fd5b50919050565b600060001982141562000980576200098062000987565b5060010190565b634e487b7160e01b600052601160045260246000fd5b614fea80620009ad6000396000f3fe608060405234801561001057600080fd5b506004361061044b5760003560e01c806301ffc9a71461045057806306fdde0314610478578063081812fc1461048d57806308a1f67f146104ad578063095ea7b3146104ce5780630dfc4ef9146104e3578063172a327e146104ec5780631c1b8772146104f55780631dbe17e51461050857806323b872dd1461051b578063297e07621461052e5780632ae6ddc3146105415780632e915ad814610554578063328b18a5146105675780633c1bd083146105705780633eab2b481461058357806342842e0e14610596578063443c0aa4146105a957806346bce096146105c9578063484f4ea9146105e957806349d4d80c146105fc5780634b2dfa7b1461060f5780634bd9351b1461062257806353294b701461062b5780635616f3251461064b578063570be5a11461066b5780636136c1561461067e57806361e1fa751461069e578063634ddfd8146106b15780636352211e146106c4578063671d2a76146106d757806367d13e99146106e05780636841b0a9146106f35780636b7979e8146107135780636ef3a27a1461071b578063706e2dfd1461072e57806370a082311461074e57806370c7038314610761578063715018a614610774578063724039f11461077c578063782300d51461078f5780637c209fc6146107b25780637e65c6f6146107c5578063813e551c146107d857806381c9db77146107f857806382210e5f1461081857806382d706ad1461082b57806384370b7a1461083e57806385c2214e14610847578063895694bf1461085a5780638d5791dc1461086d5780638d859f3e1461088d5780638da5cb5b1461089d57806390a97cb2146108a55780639106e0be146108b857806391dbff7a146108d857806394a05be7146108eb57806395d89b41146108fe5780639694dee514610906578063998ed59614610919578063a1df30731461092c578063a22cb4651461093f578063a621283114610952578063a653bfdc14610965578063aec2054b14610985578063b27d1b7e14610994578063b88d4fde146109a7578063bb53ac39146109ba578063bd8cd14e146109cd578063c04a5414146109ed578063c4a1eefc14610a08578063c757483914610a17578063c7a0e1dc14610a2a578063c87b56dd14610a4d578063c8aaf64b146104e1578063cab34c0814610985578063cafb7bec14610a60578063cb9f22c614610a73578063d3be604514610a93578063d6003e4e14610aa6578063d8f8924514610ac6578063da74d74214610ad9578063da7e928514610aec578063dad964f414610aff578063de66b4c414610b1e578063de88a3ba14610b31578063deaec42c14610b44578063e1aaa2fa14610b57578063e1cdc6f714610b6a578063e681204114610b8a578063e985e9c514610baa578063eb20feab14610bbd578063ec3bc7b114610bd0578063ecd8966414610be3578063f26716c514610c03578063f2fde38b14610c0b578063f3e3f99414610c1e575b600080fd5b61046361045e3660046149c6565b610c27565b60405190151581526020015b60405180910390f35b610480610c79565b60405161046f9190614d9e565b6104a061049b366004614c45565b610d0b565b60405161046f9190614d10565b6104c06104bb366004614c77565b610d32565b60405190815260200161046f565b6104e16104dc36600461497d565b610d63565b005b6104c0603c5481565b6104c060365481565b6104e161050336600461481c565b610dc3565b600f546104a0906001600160a01b031681565b6104e161052936600461488f565b610e39565b6104c061053c366004614c77565b610e57565b6104e161054f366004614c77565b610e73565b6104e161056236600461481c565b610f34565b6104c060175481565b61048061057e366004614c45565b610f74565b6104c0610591366004614c77565b61100e565b6104e16105a436600461488f565b61102a565b6104c06105b7366004614c45565b60236020526000908152604090205481565b6104c06105d7366004614c45565b60226020526000908152604090205481565b600d546104a0906001600160a01b031681565b6104e161060a366004614c77565b611045565b6104e161061d36600461481c565b61109c565b6104c060145481565b6104c0610639366004614c45565b60286020526000908152604090205481565b6104c0610659366004614c45565b60246020526000908152604090205481565b6104e1610679366004614a00565b6110a4565b6104c061068c36600461481c565b60386020526000908152604090205481565b6104e16106ac366004614bb6565b611114565b6104c06106bf366004614c77565b61176f565b6104a06106d2366004614c45565b61178b565b6104c060155481565b6104e16106ee366004614ad2565b6117ac565b6104c0610701366004614c45565b603a6020526000908152604090205481565b6104c0612129565b6104e161072936600461481c565b612139565b6104c061073c366004614c45565b60256020526000908152604090205481565b6104c061075c36600461481c565b61217b565b6104c061076f366004614c77565b6121ac565b6104e16121c8565b6104e161078a366004614c77565b6121dc565b61046361079d36600461481c565b603b6020526000908152604090205460ff1681565b6104e16107c0366004614c77565b612233565b6104e16107d3366004614c77565b61228a565b6104c06107e636600461481c565b60396020526000908152604090205481565b6104c0610806366004614c45565b60266020526000908152604090205481565b6104c061082636600461497d565b6122e1565b610480610839366004614c45565b6122fd565b6104c060195481565b6104e1610855366004614c77565b612316565b6104c0610868366004614c77565b61236d565b6104c061087b366004614c45565b60336020526000908152604090205481565b6104c06801f399b1438a10000081565b6104a0612389565b600c546104a0906001600160a01b031681565b6104c06108c6366004614c45565b60216020526000908152604090205481565b6104c06108e6366004614c77565b612398565b6104e16108f936600461497d565b6123b4565b610480612445565b600e546104a0906001600160a01b031681565b6104e161092736600461497d565b612454565b6104e161093a36600461481c565b612555565b6104e161094d36600461494f565b61258e565b6104e1610960366004614c77565b612599565b6104c0610973366004614c45565b601e6020526000908152604090205481565b6104c06729a2241af62c000081565b6012546104a0906001600160a01b031681565b6104e16109b53660046148d0565b6125f0565b6010546104a0906001600160a01b031681565b6104c06109db36600461481c565b60076020526000908152604090205481565b6104a0739060723c22de586c2fa5efa07a7743f6f4a935f581565b6104c067a688906bd8b0000081565b6013546104a0906001600160a01b031681565b610463610a3836600461481c565b601a6020526000908152604090205460ff1681565b610480610a5b366004614c45565b61260f565b6104c0610a6e366004614c77565b61261a565b6104c0610a81366004614c45565b60296020526000908152604090205481565b6104e1610aa1366004614c77565b612636565b6104c0610ab436600461481c565b603d6020526000908152604090205481565b6104c0610ad436600461481c565b61268d565b610480610ae7366004614c45565b61270e565b610463610afa366004614c45565b612727565b6104c0610b0d366004614c45565b602080526000908152604090205481565b6104e1610b2c366004614c77565b6128c4565b6011546104a0906001600160a01b031681565b600b546104a0906001600160a01b031681565b610480610b65366004614c45565b61291b565b6104c0610b78366004614c45565b60276020526000908152604090205481565b6104c0610b9836600461481c565b60376020526000908152604090205481565b610463610bb8366004614856565b612934565b6104c0610bcb366004614c77565b612962565b6104e1610bde36600461481c565b61297e565b6104c0610bf1366004614c45565b60346020526000908152604090205481565b6104e16129c0565b6104e1610c1936600461481c565b612aee565b6104c060355481565b60006001600160e01b031982166380ac58cd60e01b1480610c5857506001600160e01b03198216635b5e139f60e01b145b80610c7357506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060008054610c8890614e71565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb490614e71565b8015610d015780601f10610cd657610100808354040283529160200191610d01565b820191906000526020600020905b815481529060010190602001808311610ce457829003601f168201915b5050505050905090565b6000610d1682612b2e565b506000908152600460205260409020546001600160a01b031690565b602f6020528160005260406000208181548110610d4e57600080fd5b90600052602060002001600091509150505481565b6000610d6e8261178b565b9050806001600160a01b0316836001600160a01b03161415610d8f57600080fd5b336001600160a01b0382161480610dab5750610dab8133612934565b610db457600080fd5b610dbe8383612b40565b505050565b600c546040516337f9ed1360e01b81526001600160a01b03909116906337f9ed1390610df3908490600401614d10565b600060405180830381600087803b158015610e0d57600080fd5b505af1158015610e21573d6000803e3d6000fd5b50505050610e2d612bae565b610e3681612d6b565b50565b610e433382612ecb565b610e4c57600080fd5b610dbe838383612f2a565b602c6020528160005260406000208181548110610d4e57600080fd5b600b546001600160a01b03163314610e89575050565b60008281526030602052604090819020600a5491516332bedefb60e21b815290916001600160a01b03169063cafb7bec90610eca9086908690600401614db1565b60206040518083038186803b158015610ee257600080fd5b505afa158015610ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1a9190614c5e565b815460018101835560009283526020909220909101555050565b33739060723c22de586c2fa5efa07a7743f6f4a935f514610f525750565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b601f6020526000908152604090208054610f8d90614e71565b80601f0160208091040260200160405190810160405280929190818152602001828054610fb990614e71565b80156110065780601f10610fdb57610100808354040283529160200191611006565b820191906000526020600020905b815481529060010190602001808311610fe957829003601f168201915b505050505081565b602a6020528160005260406000208181548110610d4e57600080fd5b610dbe838383604051806020016040528060008152506125f0565b600b546001600160a01b0316331461105b575050565b6000828152602b602052604090819020600a5491516348edffbd60e11b815290916001600160a01b0316906391dbff7a90610eca9086908690600401614db1565b610e2d612bae565b33739060723c22de586c2fa5efa07a7743f6f4a935f5146110c457600080fd5b600f80546001600160a01b039586166001600160a01b0319918216179091556011805494861694821694909417909355601080549285169284169290921790915560128054919093169116179055565b61111d8161178b565b6001600160a01b0316336001600160a01b03161461113a57600080fd5b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061117790339030906801f399b1438a10000090600401614d24565b602060405180830381600087803b15801561119157600080fd5b505af11580156111a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c991906149a9565b50600c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611206903390309067a688906bd8b0000090600401614d24565b602060405180830381600087803b15801561122057600080fd5b505af1158015611234573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125891906149a9565b50600d5460135460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb92611297929116906729a2241af62c000090600401614d85565b602060405180830381600087803b1580156112b157600080fd5b505af11580156112c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e991906149a9565b506000818152601b60209081526040909120855161130992870190614725565b506000818152601c60209081526040909120845161132992860190614725565b506000818152601d60209081526040909120835161134992850190614725565b506729a2241af62c0000603560008282546113649190614e16565b9091555050600f546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b1580156113b657600080fd5b505af11580156113ca573d6000803e3d6000fd5b5050600d54600f5460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb935061140d92909116906729a2241af62c000090600401614d85565b602060405180830381600087803b15801561142757600080fd5b505af115801561143b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145f91906149a9565b506010546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b1580156114ad57600080fd5b505af11580156114c1573d6000803e3d6000fd5b5050600c5460105460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb935061150492909116906753444835ec58000090600401614d85565b602060405180830381600087803b15801561151e57600080fd5b505af1158015611532573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155691906149a9565b506012546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b1580156115a457600080fd5b505af11580156115b8573d6000803e3d6000fd5b5050600c5460125460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb93506115fb92909116906753444835ec58000090600401614d85565b602060405180830381600087803b15801561161557600080fd5b505af1158015611629573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164d91906149a9565b506011546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b15801561169b57600080fd5b505af11580156116af573d6000803e3d6000fd5b5050600d5460125460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb93506116f292909116906729a2241af62c000090600401614d85565b602060405180830381600087803b15801561170c57600080fd5b505af1158015611720573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174491906149a9565b5060008181526033602052604081205461176091839190613033565b61176933610dc3565b50505050565b60316020528160005260406000208181548110610d4e57600080fd5b600080611797836131e3565b90506001600160a01b038116610c7357600080fd5b600060076000600c60009054906101000a90046001600160a01b03166001600160a01b031663b1ea10336040518163ffffffff1660e01b815260040160206040518083038186803b15801561180057600080fd5b505afa158015611814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118389190614839565b6001600160a01b031681526020810191909152604001600020549050821561185d5750815b80611866575060085b601654811061187457600080fd5b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906118b190339030906801f399b1438a10000090600401614d24565b602060405180830381600087803b1580156118cb57600080fd5b505af11580156118df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190391906149a9565b50600c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611940903390309067a688906bd8b0000090600401614d24565b602060405180830381600087803b15801561195a57600080fd5b505af115801561196e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199291906149a9565b50600d5460135460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb926119d1929116906729a2241af62c000090600401614d85565b602060405180830381600087803b1580156119eb57600080fd5b505af11580156119ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2391906149a9565b50611a2d33612d6b565b600e543360009081526007602052604090819020549051633d9fa62360e01b81526001600160a01b0390921691633d9fa62391611a709160040190815260200190565b600060405180830381600087803b158015611a8a57600080fd5b505af1158015611a9e573d6000803e3d6000fd5b505050506000611aad60165490565b9050611abd601680546001019055565b611ac733826131fe565b611ad18187613218565b6000818152601b602090815260409091208a51611af0928c0190614725565b506000818152601c602090815260409091208951611b10928b0190614725565b506000818152601d602090815260409091208851611b30928a0190614725565b506000818152603360209081526040808320859055601f82529091208651611b5a92880190614725565b506000818152601e602090815260408083208690553383526007909152902054611b91573360009081526007602052604090208190555b3360009081526006602090815260408220805460018101825590835290822001829055603580546729a2241af62c00009290611bce908490614e16565b90915550506010546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611c2057600080fd5b505af1158015611c34573d6000803e3d6000fd5b5050600c5460105460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611c7792909116906753444835ec58000090600401614d85565b602060405180830381600087803b158015611c9157600080fd5b505af1158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc991906149a9565b50600f546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611d1757600080fd5b505af1158015611d2b573d6000803e3d6000fd5b5050600d54600f5460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611d6e92909116906729a2241af62c000090600401614d85565b602060405180830381600087803b158015611d8857600080fd5b505af1158015611d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc091906149a9565b506012546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611e0e57600080fd5b505af1158015611e22573d6000803e3d6000fd5b5050600c5460125460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611e6592909116906753444835ec58000090600401614d85565b602060405180830381600087803b158015611e7f57600080fd5b505af1158015611e93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb791906149a9565b506011546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611f0557600080fd5b505af1158015611f19573d6000803e3d6000fd5b5050600d5460115460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611f5c92909116906729a2241af62c000090600401614d85565b602060405180830381600087803b158015611f7657600080fd5b505af1158015611f8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fae91906149a9565b50611fbb81836001613033565b611fc433610dc3565b603a6000600c60009054906101000a90046001600160a01b03166001600160a01b0316636190c9d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561201657600080fd5b505afa15801561202a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204e9190614c5e565b8152602001908152602001600020600081548092919061206d90614eac565b9091555050336000908152603b602052604090205460ff166120b757336000908152603b60205260408120805460ff19166001179055603c8054916120b183614eac565b91905055505b60405133906120c7908990614cc5565b60405180910390208a6040516120dd9190614cc5565b60405180910390207f348a2af61c3e551d263eaa8735e61cbaaa4dbbcde2de30c684dd75431e5088d78442604051612116929190614db1565b60405180910390a4505050505050505050565b600061213460165490565b905090565b33739060723c22de586c2fa5efa07a7743f6f4a935f51461215957600080fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b03821661219057600080fd5b506001600160a01b031660009081526003602052604090205490565b602e6020528160005260406000208181548110610d4e57600080fd5b6121d0613249565b6121da6000613265565b565b600b546001600160a01b031633146121f2575050565b6000828152602e602052604090819020600a5491516370c7038360e01b815290916001600160a01b0316906370c7038390610eca9086908690600401614db1565b600b546001600160a01b03163314612249575050565b6000828152602d602052604090819020600a54915163895694bf60e01b815290916001600160a01b03169063895694bf90610eca9086908690600401614db1565b600b546001600160a01b031633146122a0575050565b60008281526032602052604090819020600a54915163eb20feab60e01b815290916001600160a01b03169063eb20feab90610eca9086908690600401614db1565b60066020528160005260406000208181548110610d4e57600080fd5b601d6020526000908152604090208054610f8d90614e71565b600b546001600160a01b0316331461232c575050565b6000828152602a602052604090819020600a5491516307d5656960e31b815290916001600160a01b031690633eab2b4890610eca9086908690600401614db1565b602d6020528160005260406000208181548110610d4e57600080fd5b6009546001600160a01b031690565b602b6020528160005260406000208181548110610d4e57600080fd5b600b546001600160a01b031633146123ca575050565b6123d3816132b7565b6001600160a01b03821660009081526006602090815260408220805460018101825590835291200181905561240882826131fe565b6001600160a01b038216600090815260076020526040902054612441576001600160a01b03821660009081526007602052604090208190555b5050565b606060018054610c8890614e71565b60165481111561246357600080fd5b61246c8161178b565b6001600160a01b0316336001600160a01b031614806124955750600b546001600160a01b031633145b6124f55760405162461bcd60e51b815260206004820152602760248201527f57616c6c6574206e6f74207175616c696669656420746f207365744661766f756044820152661c9a5d1953919560ca1b606482015260840160405180910390fd5b6001600160a01b03821660009081526007602052604090819020805490839055905133907ff1920cbfe18dff4155b1e46e979d6d82313c39f04760c14fbb8f37a21b36e912906125489084908690614db1565b60405180910390a2505050565b6013546001600160a01b0316331461256c57600080fd5b601380546001600160a01b0319166001600160a01b0392909216919091179055565b612441338383613bf9565b600b546001600160a01b031633146125af575050565b6000828152602f602052604090819020600a5491516308a1f67f60e01b815290916001600160a01b0316906308a1f67f90610eca9086908690600401614db1565b6125fa3383612ecb565b61260357600080fd5b61176984848484613c85565b6060610c7382613ca5565b60306020528160005260406000208181548110610d4e57600080fd5b600b546001600160a01b0316331461264c575050565b60008281526031602052604090819020600a549151630c69bbfb60e31b815290916001600160a01b03169063634ddfd890610eca9086908690600401614db1565b600c546040516370a0823160e01b81526000916001600160a01b0316906370a08231906126be908590600401614d10565b60206040518083038186803b1580156126d657600080fd5b505afa1580156126ea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c739190614c5e565b601b6020526000908152604090208054610f8d90614e71565b600c546000906001600160a01b0316637ba14d8c6127448461178b565b6040518263ffffffff1660e01b81526004016127609190614d10565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b091906149a9565b80610c735750600c546001600160a01b0316636252b6fd6127d08461178b565b600c5460408051636190c9d560e01b815290516001926001600160a01b031691636190c9d5916004808301926020929190829003018186803b15801561281557600080fd5b505afa158015612829573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284d9190614c5e565b6128579190614e2e565b6040518363ffffffff1660e01b8152600401612874929190614d85565b60206040518083038186803b15801561288c57600080fd5b505afa1580156128a0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7391906149a9565b600b546001600160a01b031633146128da575050565b6000828152602c602052604090819020600a5491516314bf03b160e11b815290916001600160a01b03169063297e076290610eca9086908690600401614db1565b601c6020526000908152604090208054610f8d90614e71565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60326020528160005260406000208181548110610d4e57600080fd5b33739060723c22de586c2fa5efa07a7743f6f4a935f51461299e57600080fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600b546001600160a01b031633146129d457565b6000805b6009811015612441576013546129f7906001600160a01b0316826131fe565b612a00816132b7565b600a5460405163d940848960e01b8152600481018390526001600160a01b039091169063d94084899060240160206040518083038186803b158015612a4457600080fd5b505afa158015612a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7c9190614c5e565b612a869083614e16565b6013546001600160a01b03166000908152600660209081526040808320805460018101825590845292829020909201849055815160608101909252603c808352929450612adc92849291614f5990830139613218565b80612ae681614eac565b9150506129d8565b612af6613249565b6001600160a01b038116612b0957600080fd5b610e3681613265565b5490565b80546001019055565b6001600160a01b03163b151590565b612b3781613dae565b610e3657600080fd5b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612b758261178b565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6015544211156121da57600f60009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612c0857600080fd5b505af1158015612c1c573d6000803e3d6000fd5b50505050601060009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612c7057600080fd5b505af1158015612c84573d6000803e3d6000fd5b50505050601160009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612cd857600080fd5b505af1158015612cec573d6000803e3d6000fd5b50505050601260009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d4057600080fd5b505af1158015612d54573d6000803e3d6000fd5b5050505060145442612d669190614e16565b601555565b6001600160a01b0381166000908152601a602052604090205460ff1615612deb576001600160a01b0381166000908152603d60205260408120546019805491929091612db8908490614e2e565b90915550506001600160a01b0381166000908152603d60209081526040808320839055601a9091529020805460ff191690555b600c54604051631ee8536360e21b81526001600160a01b0390911690637ba14d8c90612e1b908490600401614d10565b60206040518083038186803b158015612e3357600080fd5b505afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b91906149a9565b15610e3657612e798161217b565b60196000828254612e8a9190614e16565b90915550612e9990508161217b565b6001600160a01b0382166000908152603d6020908152604080832093909355601a905220805460ff1916600117905550565b600080612ed78361178b565b9050806001600160a01b0316846001600160a01b03161480612efe5750612efe8185612934565b80612f225750836001600160a01b0316612f1784610d0b565b6001600160a01b0316145b949350505050565b826001600160a01b0316612f3d8261178b565b6001600160a01b031614612f5057600080fd5b6001600160a01b038216612f6357600080fd5b826001600160a01b0316612f768261178b565b6001600160a01b031614612f8957600080fd5b600081815260046020526040902080546001600160a01b0319169055612faf8184613dcb565b6001600160a01b03831660009081526003602052604090208054600019019055612fd98183613f8c565b6001600160a01b03808316600081815260036020908152604080832080546001019055858352600290915280822080546001600160a01b03191684179055518493871691600080516020614f9583398151915291a4505050565b6000805b60098110156131dc57821561305157613051818686613fe0565b61305a8461178b565b6001600160a01b038116600090815260376020526040812080549294506729a2241af62c00009290919061308f908490614e16565b9091555050600084815260346020526040812080546729a2241af62c000092906130ba908490614e16565b925050819055506729a2241af62c0000603660008282546130db9190614e16565b9091555050600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061311a9085906729a2241af62c000090600401614d85565b602060405180830381600087803b15801561313457600080fd5b505af1158015613148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061316c91906149a9565b5042826001600160a01b03167fa421b4aced6f4fcb40d755e461bb29417a90636ae4f2769ff2cb29db7eab7994866729a2241af62c00006040516131b1929190614db1565b60405180910390a36000938452603360205260409093205492806131d481614eac565b915050613037565b5050505050565b6000908152600260205260409020546001600160a01b031690565b61244182826040518060200160405280600081525061438c565b61322182613dae565b61322a57600080fd5b60008281526008602090815260409091208251610dbe92840190614725565b33613252612389565b6001600160a01b0316146121da57600080fd5b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600a54604051636d3a6ba160e11b8152600481018390526001600160a01b039091169063da74d7429060240160006040518083038186803b1580156132fb57600080fd5b505afa15801561330f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526133379190810190614a5c565b6000828152601b60209081526040909120825161335a9391929190910190614725565b50600a546040516370d5517d60e11b8152600481018390526001600160a01b039091169063e1aaa2fa9060240160006040518083038186803b15801561339f57600080fd5b505afa1580156133b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526133db9190810190614a5c565b6000828152601c6020908152604090912082516133fe9391929190910190614725565b50600a546040516382d706ad60e01b8152600481018390526001600160a01b03909116906382d706ad9060240160006040518083038186803b15801561344357600080fd5b505afa158015613457573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261347f9190810190614a5c565b6000828152601d6020908152604090912082516134a29391929190910190614725565b50600a54604051632994eff760e21b8152600481018390526001600160a01b039091169063a653bfdc9060240160206040518083038186803b1580156134e757600080fd5b505afa1580156134fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351f9190614c5e565b6000828152601e60205260409081902091909155600a549051633c1bd08360e01b8152600481018390526001600160a01b0390911690633c1bd0839060240160006040518083038186803b15801561357657600080fd5b505afa15801561358a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135b29190810190614a5c565b6000828152601f6020908152604090912082516135d59391929190910190614725565b50600a54604051632355e47760e21b8152600481018390526001600160a01b0390911690638d5791dc9060240160206040518083038186803b15801561361a57600080fd5b505afa15801561362e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136529190614c5e565b6000828152603360205260409081902091909155600a5490516336b6593d60e21b8152600481018390526001600160a01b039091169063dad964f49060240160206040518083038186803b1580156136a957600080fd5b505afa1580156136bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e19190614c5e565b60008281526020805260409081902091909155600a549051634883705f60e11b8152600481018390526001600160a01b0390911690639106e0be9060240160206040518083038186803b15801561373757600080fd5b505afa15801561374b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376f9190614c5e565b6000828152602160205260409081902091909155600a54905163235e704b60e11b8152600481018390526001600160a01b03909116906346bce0969060240160206040518083038186803b1580156137c657600080fd5b505afa1580156137da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137fe9190614c5e565b6000828152602260205260409081902091909155600a54905163110f02a960e21b8152600481018390526001600160a01b039091169063443c0aa49060240160206040518083038186803b15801561385557600080fd5b505afa158015613869573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061388d9190614c5e565b6000828152602360205260409081902091909155600a549051635616f32560e01b8152600481018390526001600160a01b0390911690635616f3259060240160206040518083038186803b1580156138e457600080fd5b505afa1580156138f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061391c9190614c5e565b60008281526024602081905260409182902092909255600a54905163706e2dfd60e01b8152600481018490526001600160a01b039091169163706e2dfd910160206040518083038186803b15801561397357600080fd5b505afa158015613987573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139ab9190614c5e565b6000828152602560205260409081902091909155600a5490516381c9db7760e01b8152600481018390526001600160a01b03909116906381c9db779060240160206040518083038186803b158015613a0257600080fd5b505afa158015613a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3a9190614c5e565b6000828152602660205260409081902091909155600a54905163e1cdc6f760e01b8152600481018390526001600160a01b039091169063e1cdc6f79060240160206040518083038186803b158015613a9157600080fd5b505afa158015613aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac99190614c5e565b6000828152602760205260409081902091909155600a54905163053294b760e41b8152600481018390526001600160a01b03909116906353294b709060240160206040518083038186803b158015613b2057600080fd5b505afa158015613b34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b589190614c5e565b6000828152602860205260409081902091909155600a5490516365cf916360e11b8152600481018390526001600160a01b039091169063cb9f22c69060240160206040518083038186803b158015613baf57600080fd5b505afa158015613bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613be79190614c5e565b60009182526029602052604090912055565b816001600160a01b0316836001600160a01b03161415613c1857600080fd5b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b613c90848484612f2a565b613c9c848484846143ac565b61176957600080fd5b6060613cb082612b2e565b60008281526008602052604081208054613cc990614e71565b80601f0160208091040260200160405190810160405280929190818152602001828054613cf590614e71565b8015613d425780601f10613d1757610100808354040283529160200191613d42565b820191906000526020600020905b815481529060010190602001808311613d2557829003601f168201915b505050505090506000613d6060408051602081019091526000815290565b9050805160001415613d73575092915050565b815115613da5578082604051602001613d8d929190614ce1565b60405160208183030381529060405292505050919050565b612f22846144ad565b600080613dba836131e3565b6001600160a01b0316141592915050565b60005b6001600160a01b0382166000908152600660205260409020805484919083908110613dfb57613dfb614ef3565b906000526020600020015414613e1d5780613e1581614eac565b915050613dce565b6001600160a01b038216600090815260036020526040902054613e4290600190614e2e565b811015613edb576001600160a01b0382166000908152600660205260409020613e6c826001614e16565b81548110613e7c57613e7c614ef3565b906000526020600020015460066000846001600160a01b03166001600160a01b031681526020019081526020016000208281548110613ebd57613ebd614ef3565b60009182526020909120015580613ed381614eac565b915050613e1d565b6001600160a01b0382166000908152600660205260409020805480613f0257613f02614edd565b6000828152602080822083016000199081018390559092019092556001600160a01b0384168252600790526040902054831415610dbe576001600160a01b03821660009081526006602052604081208054909190613f6257613f62614ef3565b60009182526020808320909101546001600160a01b03851683526007909152604090912055505050565b6001600160a01b0381166000818152600660209081526040808320805460018101825590845282842001869055928252600790522054612441576001600160a01b0316600090815260076020526040902055565b826140445760008181526020805260408120805491613ffe83614eac565b9091555050600081815260296020526040812080549161401d83614eac565b90915550506000908152602a60209081526040822080546001810182559083529120015550565b82600114156140ad57600081815260216020526040812080549161406783614eac565b9091555050600081815260296020526040812080549161408683614eac565b90915550506000908152602b60209081526040822080546001810182559083529120015550565b82600214156141165760008181526022602052604081208054916140d083614eac565b909155505060008181526029602052604081208054916140ef83614eac565b90915550506000908152602c60209081526040822080546001810182559083529120015550565b826003141561417f57600081815260236020526040812080549161413983614eac565b9091555050600081815260296020526040812080549161415883614eac565b90915550506000908152602d60209081526040822080546001810182559083529120015550565b82600414156141e85760008181526024602052604081208054916141a283614eac565b909155505060008181526029602052604081208054916141c183614eac565b90915550506000908152602e60209081526040822080546001810182559083529120015550565b826005141561425157600081815260256020526040812080549161420b83614eac565b9091555050600081815260296020526040812080549161422a83614eac565b90915550506000908152602f60209081526040822080546001810182559083529120015550565b82600614156142ba57600081815260266020526040812080549161427483614eac565b9091555050600081815260296020526040812080549161429383614eac565b90915550506000908152603060209081526040822080546001810182559083529120015550565b82600714156143235760008181526027602052604081208054916142dd83614eac565b909155505060008181526029602052604081208054916142fc83614eac565b90915550506000908152603160209081526040822080546001810182559083529120015550565b8260081415610dbe57600081815260286020526040812080549161434683614eac565b9091555050600081815260296020526040812080549161436583614eac565b90915550506000908152603260209081526040822080546001810182559083529120015550565b6143968383614521565b6143a360008484846143ac565b610dbe57600080fd5b60006143c0846001600160a01b0316612b1f565b156144a257604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906143f7903390899088908890600401614d48565b602060405180830381600087803b15801561441157600080fd5b505af1925050508015614441575060408051601f3d908101601f1916820190925261443e918101906149e3565b60015b614488573d80801561446f576040519150601f19603f3d011682016040523d82523d6000602084013e614474565b606091505b50805161448057600080fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612f22565b506001949350505050565b60606144b882612b2e565b60006144cf60408051602081019091526000815290565b905060008151116144ef576040518060200160405280600081525061451a565b806144f9846145b3565b60405160200161450a929190614ce1565b6040516020818303038152906040525b9392505050565b6001600160a01b03821661453457600080fd5b61453d81613dae565b1561454757600080fd5b61455081613dae565b1561455a57600080fd5b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020614f95833981519152908290a45050565b606060006145c08361464f565b60010190506000816001600160401b038111156145df576145df614f09565b6040519080825280601f01601f191660200182016040528015614609576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461464257614647565b614613565b509392505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061468e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b83106146b8576904ee2d6d415b85acef8160201b830492506020015b662386f26fc1000083106146d657662386f26fc10000830492506010015b6305f5e10083106146ee576305f5e100830492506008015b612710831061470257612710830492506004015b60648310614714576064830492506002015b600a8310610c735760010192915050565b82805461473190614e71565b90600052602060002090601f0160209004810192826147535760008555614799565b82601f1061476c57805160ff1916838001178555614799565b82800160010185558215614799579182015b8281111561479957825182559160200191906001019061477e565b506147a59291506147a9565b5090565b5b808211156147a557600081556001016147aa565b60006147d16147cc84614def565b614dbf565b90508281528383830111156147e557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261480d57600080fd5b61451a838335602085016147be565b60006020828403121561482e57600080fd5b813561451a81614f1f565b60006020828403121561484b57600080fd5b815161451a81614f1f565b6000806040838503121561486957600080fd5b823561487481614f1f565b9150602083013561488481614f1f565b809150509250929050565b6000806000606084860312156148a457600080fd5b83356148af81614f1f565b925060208401356148bf81614f1f565b929592945050506040919091013590565b600080600080608085870312156148e657600080fd5b84356148f181614f1f565b9350602085013561490181614f1f565b92506040850135915060608501356001600160401b0381111561492357600080fd5b8501601f8101871361493457600080fd5b614943878235602084016147be565b91505092959194509250565b6000806040838503121561496257600080fd5b823561496d81614f1f565b9150602083013561488481614f34565b6000806040838503121561499057600080fd5b823561499b81614f1f565b946020939093013593505050565b6000602082840312156149bb57600080fd5b815161451a81614f34565b6000602082840312156149d857600080fd5b813561451a81614f42565b6000602082840312156149f557600080fd5b815161451a81614f42565b60008060008060808587031215614a1657600080fd5b8435614a2181614f1f565b93506020850135614a3181614f1f565b92506040850135614a4181614f1f565b91506060850135614a5181614f1f565b939692955090935050565b600060208284031215614a6e57600080fd5b81516001600160401b03811115614a8457600080fd5b8201601f81018413614a9557600080fd5b8051614aa36147cc82614def565b818152856020838501011115614ab857600080fd5b614ac9826020830160208601614e45565b95945050505050565b600080600080600080600060e0888a031215614aed57600080fd5b87356001600160401b0380821115614b0457600080fd5b614b108b838c016147fc565b985060208a0135915080821115614b2657600080fd5b614b328b838c016147fc565b975060408a0135915080821115614b4857600080fd5b614b548b838c016147fc565b965060608a0135915080821115614b6a57600080fd5b614b768b838c016147fc565b955060808a0135915080821115614b8c57600080fd5b50614b998a828b016147fc565b93505060a0880135915060c0880135905092959891949750929550565b60008060008060808587031215614bcc57600080fd5b84356001600160401b0380821115614be357600080fd5b614bef888389016147fc565b95506020870135915080821115614c0557600080fd5b614c11888389016147fc565b94506040870135915080821115614c2757600080fd5b50614c34878288016147fc565b949793965093946060013593505050565b600060208284031215614c5757600080fd5b5035919050565b600060208284031215614c7057600080fd5b5051919050565b60008060408385031215614c8a57600080fd5b50508035926020909101359150565b60008151808452614cb1816020860160208601614e45565b601f01601f19169290920160200192915050565b60008251614cd7818460208701614e45565b9190910192915050565b60008351614cf3818460208801614e45565b835190830190614d07818360208801614e45565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614d7b90830184614c99565b9695505050505050565b6001600160a01b03929092168252602082015260400190565b60208152600061451a6020830184614c99565b918252602082015260400190565b604051601f8201601f191681016001600160401b0381118282101715614de757614de7614f09565b604052919050565b60006001600160401b03821115614e0857614e08614f09565b50601f01601f191660200190565b60008219821115614e2957614e29614ec7565b500190565b600082821015614e4057614e40614ec7565b500390565b60005b83811015614e60578181015183820152602001614e48565b838111156117695750506000910152565b600181811c90821680614e8557607f821691505b60208210811415614ea657634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415614ec057614ec0614ec7565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610e3657600080fd5b8015158114610e3657600080fd5b6001600160e01b031981168114610e3657600080fdfe697066733a2f2f516d5269314476674475367a414a7770625552474e424251544d38325a434e5a4179546b454172624b5a4b6d31552f302e6a736f6eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220f0db85a3c35611b4775d04f5137da082f4100840cb359a55c06f20ea969e65d564736f6c6343000807003368747470733a2f2f7265732e636c6f7564696e6172792e636f6d2f73617665722d636f6d6d756e6974792f696d6167652f75706c6f61642f76313636363338303530312f6a766a626c73346c67356d74787378686c686e662e706e67697066733a2f2f516d5269314476674475367a414a7770625552474e424251544d38325a434e5a4179546b454172624b5a4b6d31552f3237332e6a736f6e

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061044b5760003560e01c806301ffc9a71461045057806306fdde0314610478578063081812fc1461048d57806308a1f67f146104ad578063095ea7b3146104ce5780630dfc4ef9146104e3578063172a327e146104ec5780631c1b8772146104f55780631dbe17e51461050857806323b872dd1461051b578063297e07621461052e5780632ae6ddc3146105415780632e915ad814610554578063328b18a5146105675780633c1bd083146105705780633eab2b481461058357806342842e0e14610596578063443c0aa4146105a957806346bce096146105c9578063484f4ea9146105e957806349d4d80c146105fc5780634b2dfa7b1461060f5780634bd9351b1461062257806353294b701461062b5780635616f3251461064b578063570be5a11461066b5780636136c1561461067e57806361e1fa751461069e578063634ddfd8146106b15780636352211e146106c4578063671d2a76146106d757806367d13e99146106e05780636841b0a9146106f35780636b7979e8146107135780636ef3a27a1461071b578063706e2dfd1461072e57806370a082311461074e57806370c7038314610761578063715018a614610774578063724039f11461077c578063782300d51461078f5780637c209fc6146107b25780637e65c6f6146107c5578063813e551c146107d857806381c9db77146107f857806382210e5f1461081857806382d706ad1461082b57806384370b7a1461083e57806385c2214e14610847578063895694bf1461085a5780638d5791dc1461086d5780638d859f3e1461088d5780638da5cb5b1461089d57806390a97cb2146108a55780639106e0be146108b857806391dbff7a146108d857806394a05be7146108eb57806395d89b41146108fe5780639694dee514610906578063998ed59614610919578063a1df30731461092c578063a22cb4651461093f578063a621283114610952578063a653bfdc14610965578063aec2054b14610985578063b27d1b7e14610994578063b88d4fde146109a7578063bb53ac39146109ba578063bd8cd14e146109cd578063c04a5414146109ed578063c4a1eefc14610a08578063c757483914610a17578063c7a0e1dc14610a2a578063c87b56dd14610a4d578063c8aaf64b146104e1578063cab34c0814610985578063cafb7bec14610a60578063cb9f22c614610a73578063d3be604514610a93578063d6003e4e14610aa6578063d8f8924514610ac6578063da74d74214610ad9578063da7e928514610aec578063dad964f414610aff578063de66b4c414610b1e578063de88a3ba14610b31578063deaec42c14610b44578063e1aaa2fa14610b57578063e1cdc6f714610b6a578063e681204114610b8a578063e985e9c514610baa578063eb20feab14610bbd578063ec3bc7b114610bd0578063ecd8966414610be3578063f26716c514610c03578063f2fde38b14610c0b578063f3e3f99414610c1e575b600080fd5b61046361045e3660046149c6565b610c27565b60405190151581526020015b60405180910390f35b610480610c79565b60405161046f9190614d9e565b6104a061049b366004614c45565b610d0b565b60405161046f9190614d10565b6104c06104bb366004614c77565b610d32565b60405190815260200161046f565b6104e16104dc36600461497d565b610d63565b005b6104c0603c5481565b6104c060365481565b6104e161050336600461481c565b610dc3565b600f546104a0906001600160a01b031681565b6104e161052936600461488f565b610e39565b6104c061053c366004614c77565b610e57565b6104e161054f366004614c77565b610e73565b6104e161056236600461481c565b610f34565b6104c060175481565b61048061057e366004614c45565b610f74565b6104c0610591366004614c77565b61100e565b6104e16105a436600461488f565b61102a565b6104c06105b7366004614c45565b60236020526000908152604090205481565b6104c06105d7366004614c45565b60226020526000908152604090205481565b600d546104a0906001600160a01b031681565b6104e161060a366004614c77565b611045565b6104e161061d36600461481c565b61109c565b6104c060145481565b6104c0610639366004614c45565b60286020526000908152604090205481565b6104c0610659366004614c45565b60246020526000908152604090205481565b6104e1610679366004614a00565b6110a4565b6104c061068c36600461481c565b60386020526000908152604090205481565b6104e16106ac366004614bb6565b611114565b6104c06106bf366004614c77565b61176f565b6104a06106d2366004614c45565b61178b565b6104c060155481565b6104e16106ee366004614ad2565b6117ac565b6104c0610701366004614c45565b603a6020526000908152604090205481565b6104c0612129565b6104e161072936600461481c565b612139565b6104c061073c366004614c45565b60256020526000908152604090205481565b6104c061075c36600461481c565b61217b565b6104c061076f366004614c77565b6121ac565b6104e16121c8565b6104e161078a366004614c77565b6121dc565b61046361079d36600461481c565b603b6020526000908152604090205460ff1681565b6104e16107c0366004614c77565b612233565b6104e16107d3366004614c77565b61228a565b6104c06107e636600461481c565b60396020526000908152604090205481565b6104c0610806366004614c45565b60266020526000908152604090205481565b6104c061082636600461497d565b6122e1565b610480610839366004614c45565b6122fd565b6104c060195481565b6104e1610855366004614c77565b612316565b6104c0610868366004614c77565b61236d565b6104c061087b366004614c45565b60336020526000908152604090205481565b6104c06801f399b1438a10000081565b6104a0612389565b600c546104a0906001600160a01b031681565b6104c06108c6366004614c45565b60216020526000908152604090205481565b6104c06108e6366004614c77565b612398565b6104e16108f936600461497d565b6123b4565b610480612445565b600e546104a0906001600160a01b031681565b6104e161092736600461497d565b612454565b6104e161093a36600461481c565b612555565b6104e161094d36600461494f565b61258e565b6104e1610960366004614c77565b612599565b6104c0610973366004614c45565b601e6020526000908152604090205481565b6104c06729a2241af62c000081565b6012546104a0906001600160a01b031681565b6104e16109b53660046148d0565b6125f0565b6010546104a0906001600160a01b031681565b6104c06109db36600461481c565b60076020526000908152604090205481565b6104a0739060723c22de586c2fa5efa07a7743f6f4a935f581565b6104c067a688906bd8b0000081565b6013546104a0906001600160a01b031681565b610463610a3836600461481c565b601a6020526000908152604090205460ff1681565b610480610a5b366004614c45565b61260f565b6104c0610a6e366004614c77565b61261a565b6104c0610a81366004614c45565b60296020526000908152604090205481565b6104e1610aa1366004614c77565b612636565b6104c0610ab436600461481c565b603d6020526000908152604090205481565b6104c0610ad436600461481c565b61268d565b610480610ae7366004614c45565b61270e565b610463610afa366004614c45565b612727565b6104c0610b0d366004614c45565b602080526000908152604090205481565b6104e1610b2c366004614c77565b6128c4565b6011546104a0906001600160a01b031681565b600b546104a0906001600160a01b031681565b610480610b65366004614c45565b61291b565b6104c0610b78366004614c45565b60276020526000908152604090205481565b6104c0610b9836600461481c565b60376020526000908152604090205481565b610463610bb8366004614856565b612934565b6104c0610bcb366004614c77565b612962565b6104e1610bde36600461481c565b61297e565b6104c0610bf1366004614c45565b60346020526000908152604090205481565b6104e16129c0565b6104e1610c1936600461481c565b612aee565b6104c060355481565b60006001600160e01b031982166380ac58cd60e01b1480610c5857506001600160e01b03198216635b5e139f60e01b145b80610c7357506301ffc9a760e01b6001600160e01b03198316145b92915050565b606060008054610c8890614e71565b80601f0160208091040260200160405190810160405280929190818152602001828054610cb490614e71565b8015610d015780601f10610cd657610100808354040283529160200191610d01565b820191906000526020600020905b815481529060010190602001808311610ce457829003601f168201915b5050505050905090565b6000610d1682612b2e565b506000908152600460205260409020546001600160a01b031690565b602f6020528160005260406000208181548110610d4e57600080fd5b90600052602060002001600091509150505481565b6000610d6e8261178b565b9050806001600160a01b0316836001600160a01b03161415610d8f57600080fd5b336001600160a01b0382161480610dab5750610dab8133612934565b610db457600080fd5b610dbe8383612b40565b505050565b600c546040516337f9ed1360e01b81526001600160a01b03909116906337f9ed1390610df3908490600401614d10565b600060405180830381600087803b158015610e0d57600080fd5b505af1158015610e21573d6000803e3d6000fd5b50505050610e2d612bae565b610e3681612d6b565b50565b610e433382612ecb565b610e4c57600080fd5b610dbe838383612f2a565b602c6020528160005260406000208181548110610d4e57600080fd5b600b546001600160a01b03163314610e89575050565b60008281526030602052604090819020600a5491516332bedefb60e21b815290916001600160a01b03169063cafb7bec90610eca9086908690600401614db1565b60206040518083038186803b158015610ee257600080fd5b505afa158015610ef6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1a9190614c5e565b815460018101835560009283526020909220909101555050565b33739060723c22de586c2fa5efa07a7743f6f4a935f514610f525750565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b601f6020526000908152604090208054610f8d90614e71565b80601f0160208091040260200160405190810160405280929190818152602001828054610fb990614e71565b80156110065780601f10610fdb57610100808354040283529160200191611006565b820191906000526020600020905b815481529060010190602001808311610fe957829003601f168201915b505050505081565b602a6020528160005260406000208181548110610d4e57600080fd5b610dbe838383604051806020016040528060008152506125f0565b600b546001600160a01b0316331461105b575050565b6000828152602b602052604090819020600a5491516348edffbd60e11b815290916001600160a01b0316906391dbff7a90610eca9086908690600401614db1565b610e2d612bae565b33739060723c22de586c2fa5efa07a7743f6f4a935f5146110c457600080fd5b600f80546001600160a01b039586166001600160a01b0319918216179091556011805494861694821694909417909355601080549285169284169290921790915560128054919093169116179055565b61111d8161178b565b6001600160a01b0316336001600160a01b03161461113a57600080fd5b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061117790339030906801f399b1438a10000090600401614d24565b602060405180830381600087803b15801561119157600080fd5b505af11580156111a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c991906149a9565b50600c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611206903390309067a688906bd8b0000090600401614d24565b602060405180830381600087803b15801561122057600080fd5b505af1158015611234573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125891906149a9565b50600d5460135460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb92611297929116906729a2241af62c000090600401614d85565b602060405180830381600087803b1580156112b157600080fd5b505af11580156112c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e991906149a9565b506000818152601b60209081526040909120855161130992870190614725565b506000818152601c60209081526040909120845161132992860190614725565b506000818152601d60209081526040909120835161134992850190614725565b506729a2241af62c0000603560008282546113649190614e16565b9091555050600f546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b1580156113b657600080fd5b505af11580156113ca573d6000803e3d6000fd5b5050600d54600f5460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb935061140d92909116906729a2241af62c000090600401614d85565b602060405180830381600087803b15801561142757600080fd5b505af115801561143b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145f91906149a9565b506010546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b1580156114ad57600080fd5b505af11580156114c1573d6000803e3d6000fd5b5050600c5460105460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb935061150492909116906753444835ec58000090600401614d85565b602060405180830381600087803b15801561151e57600080fd5b505af1158015611532573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155691906149a9565b506012546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b1580156115a457600080fd5b505af11580156115b8573d6000803e3d6000fd5b5050600c5460125460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb93506115fb92909116906753444835ec58000090600401614d85565b602060405180830381600087803b15801561161557600080fd5b505af1158015611629573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061164d91906149a9565b506011546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b15801561169b57600080fd5b505af11580156116af573d6000803e3d6000fd5b5050600d5460125460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb93506116f292909116906729a2241af62c000090600401614d85565b602060405180830381600087803b15801561170c57600080fd5b505af1158015611720573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174491906149a9565b5060008181526033602052604081205461176091839190613033565b61176933610dc3565b50505050565b60316020528160005260406000208181548110610d4e57600080fd5b600080611797836131e3565b90506001600160a01b038116610c7357600080fd5b600060076000600c60009054906101000a90046001600160a01b03166001600160a01b031663b1ea10336040518163ffffffff1660e01b815260040160206040518083038186803b15801561180057600080fd5b505afa158015611814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118389190614839565b6001600160a01b031681526020810191909152604001600020549050821561185d5750815b80611866575060085b601654811061187457600080fd5b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906118b190339030906801f399b1438a10000090600401614d24565b602060405180830381600087803b1580156118cb57600080fd5b505af11580156118df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190391906149a9565b50600c546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611940903390309067a688906bd8b0000090600401614d24565b602060405180830381600087803b15801561195a57600080fd5b505af115801561196e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199291906149a9565b50600d5460135460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb926119d1929116906729a2241af62c000090600401614d85565b602060405180830381600087803b1580156119eb57600080fd5b505af11580156119ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2391906149a9565b50611a2d33612d6b565b600e543360009081526007602052604090819020549051633d9fa62360e01b81526001600160a01b0390921691633d9fa62391611a709160040190815260200190565b600060405180830381600087803b158015611a8a57600080fd5b505af1158015611a9e573d6000803e3d6000fd5b505050506000611aad60165490565b9050611abd601680546001019055565b611ac733826131fe565b611ad18187613218565b6000818152601b602090815260409091208a51611af0928c0190614725565b506000818152601c602090815260409091208951611b10928b0190614725565b506000818152601d602090815260409091208851611b30928a0190614725565b506000818152603360209081526040808320859055601f82529091208651611b5a92880190614725565b506000818152601e602090815260408083208690553383526007909152902054611b91573360009081526007602052604090208190555b3360009081526006602090815260408220805460018101825590835290822001829055603580546729a2241af62c00009290611bce908490614e16565b90915550506010546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611c2057600080fd5b505af1158015611c34573d6000803e3d6000fd5b5050600c5460105460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611c7792909116906753444835ec58000090600401614d85565b602060405180830381600087803b158015611c9157600080fd5b505af1158015611ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc991906149a9565b50600f546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611d1757600080fd5b505af1158015611d2b573d6000803e3d6000fd5b5050600d54600f5460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611d6e92909116906729a2241af62c000090600401614d85565b602060405180830381600087803b158015611d8857600080fd5b505af1158015611d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dc091906149a9565b506012546040516368bf759760e01b81526753444835ec58000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611e0e57600080fd5b505af1158015611e22573d6000803e3d6000fd5b5050600c5460125460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611e6592909116906753444835ec58000090600401614d85565b602060405180830381600087803b158015611e7f57600080fd5b505af1158015611e93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb791906149a9565b506011546040516368bf759760e01b81526729a2241af62c000060048201526001600160a01b03909116906368bf759790602401600060405180830381600087803b158015611f0557600080fd5b505af1158015611f19573d6000803e3d6000fd5b5050600d5460115460405163a9059cbb60e01b81526001600160a01b03928316945063a9059cbb9350611f5c92909116906729a2241af62c000090600401614d85565b602060405180830381600087803b158015611f7657600080fd5b505af1158015611f8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fae91906149a9565b50611fbb81836001613033565b611fc433610dc3565b603a6000600c60009054906101000a90046001600160a01b03166001600160a01b0316636190c9d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561201657600080fd5b505afa15801561202a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061204e9190614c5e565b8152602001908152602001600020600081548092919061206d90614eac565b9091555050336000908152603b602052604090205460ff166120b757336000908152603b60205260408120805460ff19166001179055603c8054916120b183614eac565b91905055505b60405133906120c7908990614cc5565b60405180910390208a6040516120dd9190614cc5565b60405180910390207f348a2af61c3e551d263eaa8735e61cbaaa4dbbcde2de30c684dd75431e5088d78442604051612116929190614db1565b60405180910390a4505050505050505050565b600061213460165490565b905090565b33739060723c22de586c2fa5efa07a7743f6f4a935f51461215957600080fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b03821661219057600080fd5b506001600160a01b031660009081526003602052604090205490565b602e6020528160005260406000208181548110610d4e57600080fd5b6121d0613249565b6121da6000613265565b565b600b546001600160a01b031633146121f2575050565b6000828152602e602052604090819020600a5491516370c7038360e01b815290916001600160a01b0316906370c7038390610eca9086908690600401614db1565b600b546001600160a01b03163314612249575050565b6000828152602d602052604090819020600a54915163895694bf60e01b815290916001600160a01b03169063895694bf90610eca9086908690600401614db1565b600b546001600160a01b031633146122a0575050565b60008281526032602052604090819020600a54915163eb20feab60e01b815290916001600160a01b03169063eb20feab90610eca9086908690600401614db1565b60066020528160005260406000208181548110610d4e57600080fd5b601d6020526000908152604090208054610f8d90614e71565b600b546001600160a01b0316331461232c575050565b6000828152602a602052604090819020600a5491516307d5656960e31b815290916001600160a01b031690633eab2b4890610eca9086908690600401614db1565b602d6020528160005260406000208181548110610d4e57600080fd5b6009546001600160a01b031690565b602b6020528160005260406000208181548110610d4e57600080fd5b600b546001600160a01b031633146123ca575050565b6123d3816132b7565b6001600160a01b03821660009081526006602090815260408220805460018101825590835291200181905561240882826131fe565b6001600160a01b038216600090815260076020526040902054612441576001600160a01b03821660009081526007602052604090208190555b5050565b606060018054610c8890614e71565b60165481111561246357600080fd5b61246c8161178b565b6001600160a01b0316336001600160a01b031614806124955750600b546001600160a01b031633145b6124f55760405162461bcd60e51b815260206004820152602760248201527f57616c6c6574206e6f74207175616c696669656420746f207365744661766f756044820152661c9a5d1953919560ca1b606482015260840160405180910390fd5b6001600160a01b03821660009081526007602052604090819020805490839055905133907ff1920cbfe18dff4155b1e46e979d6d82313c39f04760c14fbb8f37a21b36e912906125489084908690614db1565b60405180910390a2505050565b6013546001600160a01b0316331461256c57600080fd5b601380546001600160a01b0319166001600160a01b0392909216919091179055565b612441338383613bf9565b600b546001600160a01b031633146125af575050565b6000828152602f602052604090819020600a5491516308a1f67f60e01b815290916001600160a01b0316906308a1f67f90610eca9086908690600401614db1565b6125fa3383612ecb565b61260357600080fd5b61176984848484613c85565b6060610c7382613ca5565b60306020528160005260406000208181548110610d4e57600080fd5b600b546001600160a01b0316331461264c575050565b60008281526031602052604090819020600a549151630c69bbfb60e31b815290916001600160a01b03169063634ddfd890610eca9086908690600401614db1565b600c546040516370a0823160e01b81526000916001600160a01b0316906370a08231906126be908590600401614d10565b60206040518083038186803b1580156126d657600080fd5b505afa1580156126ea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c739190614c5e565b601b6020526000908152604090208054610f8d90614e71565b600c546000906001600160a01b0316637ba14d8c6127448461178b565b6040518263ffffffff1660e01b81526004016127609190614d10565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b091906149a9565b80610c735750600c546001600160a01b0316636252b6fd6127d08461178b565b600c5460408051636190c9d560e01b815290516001926001600160a01b031691636190c9d5916004808301926020929190829003018186803b15801561281557600080fd5b505afa158015612829573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284d9190614c5e565b6128579190614e2e565b6040518363ffffffff1660e01b8152600401612874929190614d85565b60206040518083038186803b15801561288c57600080fd5b505afa1580156128a0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7391906149a9565b600b546001600160a01b031633146128da575050565b6000828152602c602052604090819020600a5491516314bf03b160e11b815290916001600160a01b03169063297e076290610eca9086908690600401614db1565b601c6020526000908152604090208054610f8d90614e71565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60326020528160005260406000208181548110610d4e57600080fd5b33739060723c22de586c2fa5efa07a7743f6f4a935f51461299e57600080fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600b546001600160a01b031633146129d457565b6000805b6009811015612441576013546129f7906001600160a01b0316826131fe565b612a00816132b7565b600a5460405163d940848960e01b8152600481018390526001600160a01b039091169063d94084899060240160206040518083038186803b158015612a4457600080fd5b505afa158015612a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7c9190614c5e565b612a869083614e16565b6013546001600160a01b03166000908152600660209081526040808320805460018101825590845292829020909201849055815160608101909252603c808352929450612adc92849291614f5990830139613218565b80612ae681614eac565b9150506129d8565b612af6613249565b6001600160a01b038116612b0957600080fd5b610e3681613265565b5490565b80546001019055565b6001600160a01b03163b151590565b612b3781613dae565b610e3657600080fd5b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612b758261178b565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6015544211156121da57600f60009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612c0857600080fd5b505af1158015612c1c573d6000803e3d6000fd5b50505050601060009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612c7057600080fd5b505af1158015612c84573d6000803e3d6000fd5b50505050601160009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612cd857600080fd5b505af1158015612cec573d6000803e3d6000fd5b50505050601260009054906101000a90046001600160a01b03166001600160a01b031663a2e620456040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612d4057600080fd5b505af1158015612d54573d6000803e3d6000fd5b5050505060145442612d669190614e16565b601555565b6001600160a01b0381166000908152601a602052604090205460ff1615612deb576001600160a01b0381166000908152603d60205260408120546019805491929091612db8908490614e2e565b90915550506001600160a01b0381166000908152603d60209081526040808320839055601a9091529020805460ff191690555b600c54604051631ee8536360e21b81526001600160a01b0390911690637ba14d8c90612e1b908490600401614d10565b60206040518083038186803b158015612e3357600080fd5b505afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b91906149a9565b15610e3657612e798161217b565b60196000828254612e8a9190614e16565b90915550612e9990508161217b565b6001600160a01b0382166000908152603d6020908152604080832093909355601a905220805460ff1916600117905550565b600080612ed78361178b565b9050806001600160a01b0316846001600160a01b03161480612efe5750612efe8185612934565b80612f225750836001600160a01b0316612f1784610d0b565b6001600160a01b0316145b949350505050565b826001600160a01b0316612f3d8261178b565b6001600160a01b031614612f5057600080fd5b6001600160a01b038216612f6357600080fd5b826001600160a01b0316612f768261178b565b6001600160a01b031614612f8957600080fd5b600081815260046020526040902080546001600160a01b0319169055612faf8184613dcb565b6001600160a01b03831660009081526003602052604090208054600019019055612fd98183613f8c565b6001600160a01b03808316600081815260036020908152604080832080546001019055858352600290915280822080546001600160a01b03191684179055518493871691600080516020614f9583398151915291a4505050565b6000805b60098110156131dc57821561305157613051818686613fe0565b61305a8461178b565b6001600160a01b038116600090815260376020526040812080549294506729a2241af62c00009290919061308f908490614e16565b9091555050600084815260346020526040812080546729a2241af62c000092906130ba908490614e16565b925050819055506729a2241af62c0000603660008282546130db9190614e16565b9091555050600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061311a9085906729a2241af62c000090600401614d85565b602060405180830381600087803b15801561313457600080fd5b505af1158015613148573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061316c91906149a9565b5042826001600160a01b03167fa421b4aced6f4fcb40d755e461bb29417a90636ae4f2769ff2cb29db7eab7994866729a2241af62c00006040516131b1929190614db1565b60405180910390a36000938452603360205260409093205492806131d481614eac565b915050613037565b5050505050565b6000908152600260205260409020546001600160a01b031690565b61244182826040518060200160405280600081525061438c565b61322182613dae565b61322a57600080fd5b60008281526008602090815260409091208251610dbe92840190614725565b33613252612389565b6001600160a01b0316146121da57600080fd5b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600a54604051636d3a6ba160e11b8152600481018390526001600160a01b039091169063da74d7429060240160006040518083038186803b1580156132fb57600080fd5b505afa15801561330f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526133379190810190614a5c565b6000828152601b60209081526040909120825161335a9391929190910190614725565b50600a546040516370d5517d60e11b8152600481018390526001600160a01b039091169063e1aaa2fa9060240160006040518083038186803b15801561339f57600080fd5b505afa1580156133b3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526133db9190810190614a5c565b6000828152601c6020908152604090912082516133fe9391929190910190614725565b50600a546040516382d706ad60e01b8152600481018390526001600160a01b03909116906382d706ad9060240160006040518083038186803b15801561344357600080fd5b505afa158015613457573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261347f9190810190614a5c565b6000828152601d6020908152604090912082516134a29391929190910190614725565b50600a54604051632994eff760e21b8152600481018390526001600160a01b039091169063a653bfdc9060240160206040518083038186803b1580156134e757600080fd5b505afa1580156134fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351f9190614c5e565b6000828152601e60205260409081902091909155600a549051633c1bd08360e01b8152600481018390526001600160a01b0390911690633c1bd0839060240160006040518083038186803b15801561357657600080fd5b505afa15801561358a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135b29190810190614a5c565b6000828152601f6020908152604090912082516135d59391929190910190614725565b50600a54604051632355e47760e21b8152600481018390526001600160a01b0390911690638d5791dc9060240160206040518083038186803b15801561361a57600080fd5b505afa15801561362e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136529190614c5e565b6000828152603360205260409081902091909155600a5490516336b6593d60e21b8152600481018390526001600160a01b039091169063dad964f49060240160206040518083038186803b1580156136a957600080fd5b505afa1580156136bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136e19190614c5e565b60008281526020805260409081902091909155600a549051634883705f60e11b8152600481018390526001600160a01b0390911690639106e0be9060240160206040518083038186803b15801561373757600080fd5b505afa15801561374b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376f9190614c5e565b6000828152602160205260409081902091909155600a54905163235e704b60e11b8152600481018390526001600160a01b03909116906346bce0969060240160206040518083038186803b1580156137c657600080fd5b505afa1580156137da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137fe9190614c5e565b6000828152602260205260409081902091909155600a54905163110f02a960e21b8152600481018390526001600160a01b039091169063443c0aa49060240160206040518083038186803b15801561385557600080fd5b505afa158015613869573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061388d9190614c5e565b6000828152602360205260409081902091909155600a549051635616f32560e01b8152600481018390526001600160a01b0390911690635616f3259060240160206040518083038186803b1580156138e457600080fd5b505afa1580156138f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061391c9190614c5e565b60008281526024602081905260409182902092909255600a54905163706e2dfd60e01b8152600481018490526001600160a01b039091169163706e2dfd910160206040518083038186803b15801561397357600080fd5b505afa158015613987573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139ab9190614c5e565b6000828152602560205260409081902091909155600a5490516381c9db7760e01b8152600481018390526001600160a01b03909116906381c9db779060240160206040518083038186803b158015613a0257600080fd5b505afa158015613a16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a3a9190614c5e565b6000828152602660205260409081902091909155600a54905163e1cdc6f760e01b8152600481018390526001600160a01b039091169063e1cdc6f79060240160206040518083038186803b158015613a9157600080fd5b505afa158015613aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ac99190614c5e565b6000828152602760205260409081902091909155600a54905163053294b760e41b8152600481018390526001600160a01b03909116906353294b709060240160206040518083038186803b158015613b2057600080fd5b505afa158015613b34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b589190614c5e565b6000828152602860205260409081902091909155600a5490516365cf916360e11b8152600481018390526001600160a01b039091169063cb9f22c69060240160206040518083038186803b158015613baf57600080fd5b505afa158015613bc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613be79190614c5e565b60009182526029602052604090912055565b816001600160a01b0316836001600160a01b03161415613c1857600080fd5b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b613c90848484612f2a565b613c9c848484846143ac565b61176957600080fd5b6060613cb082612b2e565b60008281526008602052604081208054613cc990614e71565b80601f0160208091040260200160405190810160405280929190818152602001828054613cf590614e71565b8015613d425780601f10613d1757610100808354040283529160200191613d42565b820191906000526020600020905b815481529060010190602001808311613d2557829003601f168201915b505050505090506000613d6060408051602081019091526000815290565b9050805160001415613d73575092915050565b815115613da5578082604051602001613d8d929190614ce1565b60405160208183030381529060405292505050919050565b612f22846144ad565b600080613dba836131e3565b6001600160a01b0316141592915050565b60005b6001600160a01b0382166000908152600660205260409020805484919083908110613dfb57613dfb614ef3565b906000526020600020015414613e1d5780613e1581614eac565b915050613dce565b6001600160a01b038216600090815260036020526040902054613e4290600190614e2e565b811015613edb576001600160a01b0382166000908152600660205260409020613e6c826001614e16565b81548110613e7c57613e7c614ef3565b906000526020600020015460066000846001600160a01b03166001600160a01b031681526020019081526020016000208281548110613ebd57613ebd614ef3565b60009182526020909120015580613ed381614eac565b915050613e1d565b6001600160a01b0382166000908152600660205260409020805480613f0257613f02614edd565b6000828152602080822083016000199081018390559092019092556001600160a01b0384168252600790526040902054831415610dbe576001600160a01b03821660009081526006602052604081208054909190613f6257613f62614ef3565b60009182526020808320909101546001600160a01b03851683526007909152604090912055505050565b6001600160a01b0381166000818152600660209081526040808320805460018101825590845282842001869055928252600790522054612441576001600160a01b0316600090815260076020526040902055565b826140445760008181526020805260408120805491613ffe83614eac565b9091555050600081815260296020526040812080549161401d83614eac565b90915550506000908152602a60209081526040822080546001810182559083529120015550565b82600114156140ad57600081815260216020526040812080549161406783614eac565b9091555050600081815260296020526040812080549161408683614eac565b90915550506000908152602b60209081526040822080546001810182559083529120015550565b82600214156141165760008181526022602052604081208054916140d083614eac565b909155505060008181526029602052604081208054916140ef83614eac565b90915550506000908152602c60209081526040822080546001810182559083529120015550565b826003141561417f57600081815260236020526040812080549161413983614eac565b9091555050600081815260296020526040812080549161415883614eac565b90915550506000908152602d60209081526040822080546001810182559083529120015550565b82600414156141e85760008181526024602052604081208054916141a283614eac565b909155505060008181526029602052604081208054916141c183614eac565b90915550506000908152602e60209081526040822080546001810182559083529120015550565b826005141561425157600081815260256020526040812080549161420b83614eac565b9091555050600081815260296020526040812080549161422a83614eac565b90915550506000908152602f60209081526040822080546001810182559083529120015550565b82600614156142ba57600081815260266020526040812080549161427483614eac565b9091555050600081815260296020526040812080549161429383614eac565b90915550506000908152603060209081526040822080546001810182559083529120015550565b82600714156143235760008181526027602052604081208054916142dd83614eac565b909155505060008181526029602052604081208054916142fc83614eac565b90915550506000908152603160209081526040822080546001810182559083529120015550565b8260081415610dbe57600081815260286020526040812080549161434683614eac565b9091555050600081815260296020526040812080549161436583614eac565b90915550506000908152603260209081526040822080546001810182559083529120015550565b6143968383614521565b6143a360008484846143ac565b610dbe57600080fd5b60006143c0846001600160a01b0316612b1f565b156144a257604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906143f7903390899088908890600401614d48565b602060405180830381600087803b15801561441157600080fd5b505af1925050508015614441575060408051601f3d908101601f1916820190925261443e918101906149e3565b60015b614488573d80801561446f576040519150601f19603f3d011682016040523d82523d6000602084013e614474565b606091505b50805161448057600080fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612f22565b506001949350505050565b60606144b882612b2e565b60006144cf60408051602081019091526000815290565b905060008151116144ef576040518060200160405280600081525061451a565b806144f9846145b3565b60405160200161450a929190614ce1565b6040516020818303038152906040525b9392505050565b6001600160a01b03821661453457600080fd5b61453d81613dae565b1561454757600080fd5b61455081613dae565b1561455a57600080fd5b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020614f95833981519152908290a45050565b606060006145c08361464f565b60010190506000816001600160401b038111156145df576145df614f09565b6040519080825280601f01601f191660200182016040528015614609576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461464257614647565b614613565b509392505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061468e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b83106146b8576904ee2d6d415b85acef8160201b830492506020015b662386f26fc1000083106146d657662386f26fc10000830492506010015b6305f5e10083106146ee576305f5e100830492506008015b612710831061470257612710830492506004015b60648310614714576064830492506002015b600a8310610c735760010192915050565b82805461473190614e71565b90600052602060002090601f0160209004810192826147535760008555614799565b82601f1061476c57805160ff1916838001178555614799565b82800160010185558215614799579182015b8281111561479957825182559160200191906001019061477e565b506147a59291506147a9565b5090565b5b808211156147a557600081556001016147aa565b60006147d16147cc84614def565b614dbf565b90508281528383830111156147e557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261480d57600080fd5b61451a838335602085016147be565b60006020828403121561482e57600080fd5b813561451a81614f1f565b60006020828403121561484b57600080fd5b815161451a81614f1f565b6000806040838503121561486957600080fd5b823561487481614f1f565b9150602083013561488481614f1f565b809150509250929050565b6000806000606084860312156148a457600080fd5b83356148af81614f1f565b925060208401356148bf81614f1f565b929592945050506040919091013590565b600080600080608085870312156148e657600080fd5b84356148f181614f1f565b9350602085013561490181614f1f565b92506040850135915060608501356001600160401b0381111561492357600080fd5b8501601f8101871361493457600080fd5b614943878235602084016147be565b91505092959194509250565b6000806040838503121561496257600080fd5b823561496d81614f1f565b9150602083013561488481614f34565b6000806040838503121561499057600080fd5b823561499b81614f1f565b946020939093013593505050565b6000602082840312156149bb57600080fd5b815161451a81614f34565b6000602082840312156149d857600080fd5b813561451a81614f42565b6000602082840312156149f557600080fd5b815161451a81614f42565b60008060008060808587031215614a1657600080fd5b8435614a2181614f1f565b93506020850135614a3181614f1f565b92506040850135614a4181614f1f565b91506060850135614a5181614f1f565b939692955090935050565b600060208284031215614a6e57600080fd5b81516001600160401b03811115614a8457600080fd5b8201601f81018413614a9557600080fd5b8051614aa36147cc82614def565b818152856020838501011115614ab857600080fd5b614ac9826020830160208601614e45565b95945050505050565b600080600080600080600060e0888a031215614aed57600080fd5b87356001600160401b0380821115614b0457600080fd5b614b108b838c016147fc565b985060208a0135915080821115614b2657600080fd5b614b328b838c016147fc565b975060408a0135915080821115614b4857600080fd5b614b548b838c016147fc565b965060608a0135915080821115614b6a57600080fd5b614b768b838c016147fc565b955060808a0135915080821115614b8c57600080fd5b50614b998a828b016147fc565b93505060a0880135915060c0880135905092959891949750929550565b60008060008060808587031215614bcc57600080fd5b84356001600160401b0380821115614be357600080fd5b614bef888389016147fc565b95506020870135915080821115614c0557600080fd5b614c11888389016147fc565b94506040870135915080821115614c2757600080fd5b50614c34878288016147fc565b949793965093946060013593505050565b600060208284031215614c5757600080fd5b5035919050565b600060208284031215614c7057600080fd5b5051919050565b60008060408385031215614c8a57600080fd5b50508035926020909101359150565b60008151808452614cb1816020860160208601614e45565b601f01601f19169290920160200192915050565b60008251614cd7818460208701614e45565b9190910192915050565b60008351614cf3818460208801614e45565b835190830190614d07818360208801614e45565b01949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090614d7b90830184614c99565b9695505050505050565b6001600160a01b03929092168252602082015260400190565b60208152600061451a6020830184614c99565b918252602082015260400190565b604051601f8201601f191681016001600160401b0381118282101715614de757614de7614f09565b604052919050565b60006001600160401b03821115614e0857614e08614f09565b50601f01601f191660200190565b60008219821115614e2957614e29614ec7565b500190565b600082821015614e4057614e40614ec7565b500390565b60005b83811015614e60578181015183820152602001614e48565b838111156117695750506000910152565b600181811c90821680614e8557607f821691505b60208210811415614ea657634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415614ec057614ec0614ec7565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610e3657600080fd5b8015158114610e3657600080fd5b6001600160e01b031981168114610e3657600080fdfe697066733a2f2f516d5269314476674475367a414a7770625552474e424251544d38325a434e5a4179546b454172624b5a4b6d31552f302e6a736f6eddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220f0db85a3c35611b4775d04f5137da082f4100840cb359a55c06f20ea969e65d564736f6c63430008070033

Deployed Bytecode Sourcemap

156973:24011:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30051:321;;;;;;:::i;:::-;;:::i;:::-;;;12012:14:1;;12005:22;11987:41;;11975:2;11960:18;30051:321:0;;;;;;;;30954:100;;;:::i;:::-;;;;;;;:::i;32390:187::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;161926:61::-;;;;;;:::i;:::-;;:::i;:::-;;;13113:25:1;;;13101:2;13086:18;161926:61:0;12941:203:1;32047:277:0;;;;;;:::i;:::-;;:::i;:::-;;162830:28;;;;;;162467:43;;;;;;175135:161;;;;;;:::i;:::-;;:::i;158181:94::-;;;;;-1:-1:-1;;;;;158181:94:0;;;33156:286;;;;;;:::i;:::-;;:::i;161718:63::-;;;;;;:::i;:::-;;:::i;167644:283::-;;;;;;:::i;:::-;;:::i;163475:180::-;;;;;;:::i;:::-;;:::i;159027:30::-;;;;;;160521:51;;;;;;:::i;:::-;;:::i;161577:63::-;;;;;;:::i;:::-;;:::i;33513:185::-;;;;;;:::i;:::-;;:::i;160913:66::-;;;;;;:::i;:::-;;;;;;;;;;;;;;160839:67;;;;;;:::i;:::-;;;;;;;;;;;;;;157957:69;;;;;-1:-1:-1;;;;;157957:69:0;;;166198:286;;;;;;:::i;:::-;;:::i;175304:124::-;;;;;;:::i;:::-;;:::i;158848:30::-;;;;;;161279:66;;;;;;:::i;:::-;;;;;;;;;;;;;;160986;;;;;;:::i;:::-;;;;;;;;;;;;;;173043:401;;;;;;:::i;:::-;;:::i;162582:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;171341:1375;;;;;;:::i;:::-;;:::i;162064:63::-;;;;;;:::i;:::-;;:::i;30676:211::-;;;;;;:::i;:::-;;:::i;158885:31::-;;;;;;168526:2807;;;;;;:::i;:::-;;:::i;162701:56::-;;;;;;:::i;:::-;;;;;;;;;;;;;;172747:107;;;:::i;175597:142::-;;;;;;:::i;:::-;;:::i;161059:65::-;;;;;;:::i;:::-;;;;;;;;;;;;;;30436:178;;;;;;:::i;:::-;;:::i;161857:62::-;;;;;;:::i;:::-;;:::i;49445:103::-;;;:::i;167071:280::-;;;;;;:::i;:::-;;:::i;162782:41::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;166783:280;;;;;;:::i;:::-;;:::i;168226:::-;;;;;;:::i;:::-;;:::i;162641:53::-;;;;;;:::i;:::-;;;;;;;;;;;;;;161131:67;;;;;;:::i;:::-;;;;;;;;;;;;;;29592:48;;;;;;:::i;:::-;;:::i;160391:56::-;;;;;;:::i;:::-;;:::i;160191:29::-;;;;;;165907:283;;;;;;:::i;:::-;;:::i;161788:62::-;;;;;;:::i;:::-;;:::i;162235:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;157052:40;;157084:8;157052:40;;48833:87;;;:::i;157881:69::-;;;;;-1:-1:-1;;;;;157881:69:0;;;160764:68;;;;;;:::i;:::-;;;;;;;;;;;;;;161647:64;;;;;;:::i;:::-;;:::i;163663:349::-;;;;;;:::i;:::-;;:::i;31123:104::-;;;:::i;158053:95::-;;;;;-1:-1:-1;;;;;158053:95:0;;;173452:412;;;;;;:::i;:::-;;:::i;173872:156::-;;;;;;:::i;:::-;;:::i;32649:180::-;;;;;;:::i;:::-;;:::i;167359:277::-;;;;;;:::i;:::-;;:::i;160454:60::-;;;;;;:::i;:::-;;;;;;;;;;;;;;157198:48;;157239:7;157198:48;;158541:96;;;;;-1:-1:-1;;;;;158541:96:0;;;33769:273;;;;;;:::i;:::-;;:::i;158282:94::-;;;;;-1:-1:-1;;;;;158282:94:0;;;29647:48;;;;;;:::i;:::-;;;;;;;;;;;;;;158744:95;;158797:42;158744:95;;157099:45;;157136:8;157099:45;;158662:75;;;;;-1:-1:-1;;;;;158662:75:0;;;160227:44;;;;;;:::i;:::-;;;;;;;;;;;;;;;;180810:171;;;;;;:::i;:::-;;:::i;161994:63::-;;;;;;:::i;:::-;;:::i;161354:62::-;;;;;;:::i;:::-;;;;;;;;;;;;;;167935:283;;;;;;:::i;:::-;;:::i;162880:57::-;;;;;;:::i;:::-;;;;;;;;;;;;;;175436:118;;;;;;:::i;:::-;;:::i;160278:46::-;;;;;;:::i;:::-;;:::i;174053:217::-;;;;;;:::i;:::-;;:::i;160690:67::-;;;;;;:::i;:::-;;;;;;;;;;;;;;166492:283;;;;;;:::i;:::-;;:::i;158438:96::-;;;;;-1:-1:-1;;;;;158438:96:0;;;157757:99;;;;;-1:-1:-1;;;;;157757:99:0;;;160331:53;;;;;;:::i;:::-;;:::i;161205:67::-;;;;;;:::i;:::-;;;;;;;;;;;;;;162517:58;;;;;;:::i;:::-;;;;;;;;;;;;;;32900:189;;;;;;:::i;:::-;;:::i;162134:62::-;;;;;;:::i;:::-;;:::i;172884:151::-;;;;;;:::i;:::-;;:::i;162312:63::-;;;;;;:::i;:::-;;;;;;;;;;;;;;176624:695;;;:::i;49703:159::-;;;;;;:::i;:::-;;:::i;162402:37::-;;;;;;30051:321;30169:4;-1:-1:-1;;;;;;30206:40:0;;-1:-1:-1;;;30206:40:0;;:105;;-1:-1:-1;;;;;;;30263:48:0;;-1:-1:-1;;;30263:48:0;30206:105;:158;;;-1:-1:-1;;;;;;;;;;28846:40:0;;;30328:36;30186:178;30051:321;-1:-1:-1;;30051:321:0:o;30954:100::-;31008:13;31041:5;31034:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30954:100;:::o;32390:187::-;32482:7;32502:23;32517:7;32502:14;:23::i;:::-;-1:-1:-1;32545:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;32545:24:0;;32390:187::o;161926:61::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;32047:277::-;32128:13;32144:23;32159:7;32144:14;:23::i;:::-;32128:39;;32192:5;-1:-1:-1;;;;;32186:11:0;:2;-1:-1:-1;;;;;32186:11:0;;;32178:20;;;;;;26114:10;-1:-1:-1;;;;;32219:21:0;;;;:62;;-1:-1:-1;32244:37:0;32261:5;26114:10;32900:189;:::i;32244:37::-;32211:71;;;;;;32295:21;32304:2;32308:7;32295:8;:21::i;:::-;32117:207;32047:277;;:::o;175135:161::-;175185:4;;:30;;-1:-1:-1;;;175185:30:0;;-1:-1:-1;;;;;175185:4:0;;;;:22;;:30;;175208:6;;175185:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;175228:18;:16;:18::i;:::-;175259:29;175281:6;175259:21;:29::i;:::-;175135:161;:::o;33156:286::-;33351:41;26114:10;33384:7;33351:18;:41::i;:::-;33343:50;;;;;;33406:28;33416:4;33422:2;33426:7;33406:9;:28::i;161718:63::-;;;;;;;;;;;;;;;;;;;;167644:283;167754:17;;-1:-1:-1;;;;;167754:17:0;167732:10;:40;167728:53;;167644:283;;:::o;167728:53::-;167793:35;;;;:26;:35;;;;;;;167848:17;;:60;;-1:-1:-1;;;167848:60:0;;167793:35;;-1:-1:-1;;;;;167848:17:0;;:44;;:60;;167820:7;;167902:5;;167848:60;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;167793:126;;;;;;;-1:-1:-1;167793:126:0;;;;;;;;;;;-1:-1:-1;;167644:283:0:o;163475:180::-;163559:10;158797:42;163559:31;163555:44;;163475:180;:::o;163555:44::-;163609:17;:38;;-1:-1:-1;;;;;;163609:38:0;-1:-1:-1;;;;;163609:38:0;;;;;;;;;;163475:180::o;160521:51::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;161577:63::-;;;;;;;;;;;;;;;;;;;;33513:185;33651:39;33668:4;33674:2;33678:7;33651:39;;;;;;;;;;;;:16;:39::i;166198:286::-;166309:17;;-1:-1:-1;;;;;166309:17:0;166287:10;:40;166283:53;;166198:286;;:::o;166283:53::-;166348:36;;;;:27;:36;;;;;;;166404:17;;:61;;-1:-1:-1;;;166404:61:0;;166348:36;;-1:-1:-1;;;;;166404:17:0;;:45;;:61;;166376:7;;166459:5;;166404:61;;;:::i;175304:124::-;175362:18;:16;:18::i;173043:401::-;173220:10;158797:42;173220:31;173212:40;;;;;;173263:18;:33;;-1:-1:-1;;;;;173263:33:0;;;-1:-1:-1;;;;;;173263:33:0;;;;;;;173307:20;:37;;;;;;;;;;;;;;;173355:18;:33;;;;;;;;;;;;;;;173399:20;:37;;;;;;;;;;;173043:401::o;171341:1375::-;171540:17;171548:8;171540:7;:17::i;:::-;-1:-1:-1;;;;;171526:31:0;:10;-1:-1:-1;;;;;171526:31:0;;171518:40;;;;;;171571:4;;:51;;-1:-1:-1;;;171571:51:0;;-1:-1:-1;;;;;171571:4:0;;;;:17;;:51;;171589:10;;171609:4;;157084:8;;171571:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;171633:4:0;;:56;;-1:-1:-1;;;171633:56:0;;-1:-1:-1;;;;;171633:4:0;;;;:17;;:56;;171651:10;;171671:4;;157136:8;;171633:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;171748:4:0;;171762:15;;171748:46;;-1:-1:-1;;;171748:46:0;;-1:-1:-1;;;;;171748:4:0;;;;:13;;:46;;171762:15;;;157239:7;;171748:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;171834:22:0;;;;:12;:22;;;;;;;;:30;;;;;;;;:::i;:::-;-1:-1:-1;171875:29:0;;;;:19;:29;;;;;;;;:44;;;;;;;;:::i;:::-;-1:-1:-1;171930:32:0;;;;:22;:32;;;;;;;;:49;;;;;;;;:::i;:::-;;157239:7;172034:22;;:40;;;;;;;:::i;:::-;;;;-1:-1:-1;;172116:18:0;;:38;;-1:-1:-1;;;172116:38:0;;172146:7;172116:38;;;13113:25:1;-1:-1:-1;;;;;172116:18:0;;;;:29;;13086:18:1;;172116:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;172165:4:0;;172187:18;;172165:51;;-1:-1:-1;;;172165:51:0;;-1:-1:-1;;;;;172165:4:0;;;;-1:-1:-1;172165:13:0;;-1:-1:-1;172165:51:0;;172187:18;;;;172208:7;;172165:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;172229:18:0;;:38;;-1:-1:-1;;;172229:38:0;;172259:7;172229:38;;;13113:25:1;-1:-1:-1;;;;;172229:18:0;;;;:29;;13086:18:1;;172229:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;172278:4:0;;172300:18;;172278:51;;-1:-1:-1;;;172278:51:0;;-1:-1:-1;;;;;172278:4:0;;;;-1:-1:-1;172278:13:0;;-1:-1:-1;172278:51:0;;172300:18;;;;172321:7;;172278:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;172342:20:0;;:40;;-1:-1:-1;;;172342:40:0;;172374:7;172342:40;;;13113:25:1;-1:-1:-1;;;;;172342:20:0;;;;:31;;13086:18:1;;172342:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;172393:4:0;;172415:20;;172393:53;;-1:-1:-1;;;172393:53:0;;-1:-1:-1;;;;;172393:4:0;;;;-1:-1:-1;172393:13:0;;-1:-1:-1;172393:53:0;;172415:20;;;;172438:7;;172393:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;172459:20:0;;:40;;-1:-1:-1;;;172459:40:0;;172491:7;172459:40;;;13113:25:1;-1:-1:-1;;;;;172459:20:0;;;;:31;;13086:18:1;;172459:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;172510:4:0;;172532:20;;172510:53;;-1:-1:-1;;;172510:53:0;;-1:-1:-1;;;;;172510:4:0;;;;-1:-1:-1;172510:13:0;;-1:-1:-1;172510:53:0;;172532:20;;;;172555:7;;172510:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;172642:27:0;;;;:17;:27;;;;;;172621:56;;172632:8;;172642:27;172621:10;:56::i;:::-;172690:18;172697:10;172690:6;:18::i;:::-;171341:1375;;;;:::o;162064:63::-;;;;;;;;;;;;;;;;;;;;30676:211;30764:7;30784:13;30800:17;30809:7;30800:8;:17::i;:::-;30784:33;-1:-1:-1;;;;;;30836:19:0;;30828:28;;;;;168526:2807;168819:18;168840:13;:38;168854:4;;;;;;;;;-1:-1:-1;;;;;168854:4:0;-1:-1:-1;;;;;168854:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;168840:38:0;;;;;;;;;;;;-1:-1:-1;168840:38:0;;;-1:-1:-1;168895:9:0;;168891:59;;-1:-1:-1;168934:4:0;168891:59;168966:15;168962:62;;-1:-1:-1;169011:1:0;168962:62;169057:9;12625:14;169044:10;:32;169036:41;;;;;;169090:4;;:51;;-1:-1:-1;;;169090:51:0;;-1:-1:-1;;;;;169090:4:0;;;;:17;;:51;;169108:10;;169128:4;;157084:8;;169090:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;169152:4:0;;:56;;-1:-1:-1;;;169152:56:0;;-1:-1:-1;;;;;169152:4:0;;;;:17;;:56;;169170:10;;169190:4;;157136:8;;169152:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;169267:4:0;;169281:15;;169267:46;;-1:-1:-1;;;169267:46:0;;-1:-1:-1;;;;;169267:4:0;;;;:13;;:46;;169281:15;;;157239:7;;169267:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;169326:33;169348:10;169326:21;:33::i;:::-;169372:9;;169408:10;169372:9;169394:25;;;:13;:25;;;;;;;;169372:48;;-1:-1:-1;;;169372:48:0;;-1:-1:-1;;;;;169372:9:0;;;;:21;;:48;;;;13113:25:1;;;13101:2;13086:18;;12941:203;169372:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;169454:15;169472:19;:9;12625:14;;12533:114;169472:19;169454:37;;169502:21;:9;12744:19;;12762:1;12744:19;;;12655:127;169502:21;169534:30;169544:10;169556:7;169534:9;:30::i;:::-;169597:27;169610:7;169619:4;169597:12;:27::i;:::-;169676:21;;;;:12;:21;;;;;;;;:29;;;;;;;;:::i;:::-;-1:-1:-1;169716:28:0;;;;:19;:28;;;;;;;;:43;;;;;;;;:::i;:::-;-1:-1:-1;169770:31:0;;;;:22;:31;;;;;;;;:48;;;;;;;;:::i;:::-;-1:-1:-1;169829:26:0;;;;:17;:26;;;;;;;;:39;;;169881:17;:26;;;;;:38;;;;;;;;:::i;:::-;-1:-1:-1;169930:34:0;;;;:25;:34;;;;;;;;:47;;;170008:10;169994:25;;:13;:25;;;;;;169990:98;;170055:10;170041:25;;;;:13;:25;;;;;:35;;;169990:98;170176:10;170164:23;;;;:11;:23;;;;;;;:37;;;;;;;;;;;;;;;;;170302:22;:40;;157239:7;;170164:23;170302:40;;157239:7;;170302:40;:::i;:::-;;;;-1:-1:-1;;170384:18:0;;:38;;-1:-1:-1;;;170384:38:0;;170414:7;170384:38;;;13113:25:1;-1:-1:-1;;;;;170384:18:0;;;;:29;;13086:18:1;;170384:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;170433:4:0;;170455:18;;170433:51;;-1:-1:-1;;;170433:51:0;;-1:-1:-1;;;;;170433:4:0;;;;-1:-1:-1;170433:13:0;;-1:-1:-1;170433:51:0;;170455:18;;;;170476:7;;170433:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;170497:18:0;;:38;;-1:-1:-1;;;170497:38:0;;170527:7;170497:38;;;13113:25:1;-1:-1:-1;;;;;170497:18:0;;;;:29;;13086:18:1;;170497:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;170546:4:0;;170568:18;;170546:51;;-1:-1:-1;;;170546:51:0;;-1:-1:-1;;;;;170546:4:0;;;;-1:-1:-1;170546:13:0;;-1:-1:-1;170546:51:0;;170568:18;;;;170589:7;;170546:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;170610:20:0;;:40;;-1:-1:-1;;;170610:40:0;;170642:7;170610:40;;;13113:25:1;-1:-1:-1;;;;;170610:20:0;;;;:31;;13086:18:1;;170610:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;170661:4:0;;170683:20;;170661:53;;-1:-1:-1;;;170661:53:0;;-1:-1:-1;;;;;170661:4:0;;;;-1:-1:-1;170661:13:0;;-1:-1:-1;170661:53:0;;170683:20;;;;170706:7;;170661:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;170727:20:0;;:40;;-1:-1:-1;;;170727:40:0;;170759:7;170727:40;;;13113:25:1;-1:-1:-1;;;;;170727:20:0;;;;:31;;13086:18:1;;170727:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;170778:4:0;;170800:20;;170778:53;;-1:-1:-1;;;170778:53:0;;-1:-1:-1;;;;;170778:4:0;;;;-1:-1:-1;170778:13:0;;-1:-1:-1;170778:53:0;;170800:20;;;;170823:7;;170778:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;170891:37;170902:7;170911:10;170923:4;170891:10;:37::i;:::-;170941:18;170948:10;170941:6;:18::i;:::-;171037:21;:35;171059:4;;;;;;;;;-1:-1:-1;;;;;171059:4:0;-1:-1:-1;;;;;171059:10:0;;:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;171037:35;;;;;;;;;;;;:37;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;171122:10:0;171112:21;;;;:9;:21;;;;;;;;171107:113;;171160:10;171150:21;;;;:9;:21;;;;;:28;;-1:-1:-1;;171150:28:0;171174:4;171150:28;;;171193:13;:15;;;;;;:::i;:::-;;;;;;171107:113;171260:65;;171314:10;;171260:65;;171298:14;;171260:65;:::i;:::-;;;;;;;;171291:5;171260:65;;;;;;:::i;:::-;;;;;;;;;171265:7;171274:15;171260:65;;;;;;;:::i;:::-;;;;;;;;168780:2553;;168526:2807;;;;;;;:::o;172747:107::-;172800:7;172827:19;:9;12625:14;;12533:114;172827:19;172820:26;;172747:107;:::o;175597:142::-;175668:10;158797:42;175668:31;175660:40;;;;;;175711:9;:20;;-1:-1:-1;;;;;;175711:20:0;-1:-1:-1;;;;;175711:20:0;;;;;;;;;;175597:142::o;30436:178::-;30524:7;-1:-1:-1;;;;;30552:19:0;;30544:28;;;;;;-1:-1:-1;;;;;;30590:16:0;;;;;:9;:16;;;;;;;30436:178::o;161857:62::-;;;;;;;;;;;;;;;;;;;;49445:103;48719:13;:11;:13::i;:::-;49510:30:::1;49537:1;49510:18;:30::i;:::-;49445:103::o:0;167071:280::-;167180:17;;-1:-1:-1;;;;;167180:17:0;167158:10;:40;167154:53;;167071:280;;:::o;167154:53::-;167219:34;;;;:25;:34;;;;;;;167273:17;;:59;;-1:-1:-1;;;167273:59:0;;167219:34;;-1:-1:-1;;;;;167273:17:0;;:43;;:59;;167245:7;;167326:5;;167273:59;;;:::i;166783:280::-;166892:17;;-1:-1:-1;;;;;166892:17:0;166870:10;:40;166866:53;;166783:280;;:::o;166866:53::-;166931:34;;;;:25;:34;;;;;;;166985:17;;:59;;-1:-1:-1;;;166985:59:0;;166931:34;;-1:-1:-1;;;;;166985:17:0;;:43;;:59;;166957:7;;167038:5;;166985:59;;;:::i;168226:280::-;168335:17;;-1:-1:-1;;;;;168335:17:0;168313:10;:40;168309:53;;168226:280;;:::o;168309:53::-;168374:34;;;;:25;:34;;;;;;;168428:17;;:59;;-1:-1:-1;;;168428:59:0;;168374:34;;-1:-1:-1;;;;;168428:17:0;;:43;;:59;;168400:7;;168481:5;;168428:59;;;:::i;29592:48::-;;;;;;;;;;;;;;;;;;;;160391:56;;;;;;;;;;;;;;;;:::i;165907:283::-;166017:17;;-1:-1:-1;;;;;166017:17:0;165995:10;:40;165991:53;;165907:283;;:::o;165991:53::-;166056:35;;;;:26;:35;;;;;;;166111:17;;:60;;-1:-1:-1;;;166111:60:0;;166056:35;;-1:-1:-1;;;;;166111:17:0;;:44;;:60;;166083:7;;166165:5;;166111:60;;;:::i;161788:62::-;;;;;;;;;;;;;;;;;;;;48833:87;48906:6;;-1:-1:-1;;;;;48906:6:0;;48833:87::o;161647:64::-;;;;;;;;;;;;;;;;;;;;163663:349;163763:17;;-1:-1:-1;;;;;163763:17:0;163741:10;:40;163737:53;;163663:349;;:::o;163737:53::-;163802:19;163813:7;163802:10;:19::i;:::-;-1:-1:-1;;;;;163832:19:0;;;;;;:11;:19;;;;;;;:33;;;;;;;;;;;;;;;;163876:26;163844:6;163857:7;163876:9;:26::i;:::-;-1:-1:-1;;;;;163919:21:0;;;;;;:13;:21;;;;;;163915:90;;-1:-1:-1;;;;;163962:21:0;;;;;;:13;:21;;;;;:31;;;163915:90;163663:349;;:::o;31123:104::-;31179:13;31212:7;31205:14;;;;;:::i;173452:412::-;173537:9;12625:14;173531:2;:25;;173523:34;;;;;;173590:11;173598:2;173590:7;:11::i;:::-;-1:-1:-1;;;;;173576:25:0;:10;-1:-1:-1;;;;;173576:25:0;;:69;;;-1:-1:-1;173627:17:0;;-1:-1:-1;;;;;173627:17:0;173605:10;:40;173576:69;173568:121;;;;-1:-1:-1;;;173568:121:0;;13783:2:1;173568:121:0;;;13765:21:1;13822:2;13802:18;;;13795:30;13861:34;13841:18;;;13834:62;-1:-1:-1;;;13912:18:1;;;13905:37;13959:19;;173568:121:0;;;;;;;;-1:-1:-1;;;;;173730:21:0;;173702:25;173730:21;;;:13;:21;;;;;;;;;173762:26;;;;173806:50;;173822:10;;173806:50;;;;173730:21;;173786:2;;173806:50;:::i;:::-;;;;;;;;173512:352;173452:412;;:::o;173872:156::-;173963:15;;-1:-1:-1;;;;;173963:15:0;173949:10;:29;173941:38;;;;;;173992:15;:28;;-1:-1:-1;;;;;;173992:28:0;-1:-1:-1;;;;;173992:28:0;;;;;;;;;;173872:156::o;32649:180::-;32769:52;26114:10;32802:8;32812;32769:18;:52::i;167359:277::-;167467:17;;-1:-1:-1;;;;;167467:17:0;167445:10;:40;167441:53;;167359:277;;:::o;167441:53::-;167506:33;;;;:24;:33;;;;;;;167559:17;;:58;;-1:-1:-1;;;167559:58:0;;167506:33;;-1:-1:-1;;;;;167559:17:0;;:42;;:58;;167531:7;;167611:5;;167559:58;;;:::i;33769:273::-;33943:41;26114:10;33976:7;33943:18;:41::i;:::-;33935:50;;;;;;33996:38;34010:4;34016:2;34020:7;34029:4;33996:13;:38::i;180810:171::-;180917:13;180950:23;180965:7;180950:14;:23::i;161994:63::-;;;;;;;;;;;;;;;;;;;;167935:283;168045:17;;-1:-1:-1;;;;;168045:17:0;168023:10;:40;168019:53;;167935:283;;:::o;168019:53::-;168084:35;;;;:26;:35;;;;;;;168139:17;;:60;;-1:-1:-1;;;168139:60:0;;168084:35;;-1:-1:-1;;;;;168139:17:0;;:44;;:60;;168111:7;;168193:5;;168139:60;;;:::i;175436:118::-;175524:4;;:22;;-1:-1:-1;;;175524:22:0;;175497:7;;-1:-1:-1;;;;;175524:4:0;;:14;;:22;;175539:6;;175524:22;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;160278:46::-;;;;;;;;;;;;;;;;:::i;174053:217::-;174155:4;;174118;;-1:-1:-1;;;;;174155:4:0;:15;174171:16;174179:7;174171;:16::i;:::-;174155:33;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:107;;;-1:-1:-1;174205:4:0;;-1:-1:-1;;;;;174205:4:0;:21;174227:16;174235:7;174227;:16::i;:::-;174245:4;;:12;;;-1:-1:-1;;;174245:12:0;;;;174260:1;;-1:-1:-1;;;;;174245:4:0;;:10;;:12;;;;;;;;;;;;;;:4;:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:16;;;;:::i;:::-;174205:57;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;166492:283::-;166602:17;;-1:-1:-1;;;;;166602:17:0;166580:10;:40;166576:53;;166492:283;;:::o;166576:53::-;166641:35;;;;:26;:35;;;;;;;166696:17;;:60;;-1:-1:-1;;;166696:60:0;;166641:35;;-1:-1:-1;;;;;166696:17:0;;:44;;:60;;166668:7;;166750:5;;166696:60;;;:::i;160331:53::-;;;;;;;;;;;;;;;;:::i;32900:189::-;-1:-1:-1;;;;;33046:25:0;;;33022:4;33046:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;32900:189::o;162134:62::-;;;;;;;;;;;;;;;;;;;;172884:151;172956:10;158797:42;172956:31;172948:40;;;;;;173001:4;:26;;-1:-1:-1;;;;;;173001:26:0;-1:-1:-1;;;;;173001:26:0;;;;;;;;;;172884:151::o;176624:695::-;176699:17;;-1:-1:-1;;;;;176699:17:0;176677:10;:40;176673:53;;176624:695::o;176673:53::-;176875:25;;176913:399;176937:1;176933;:5;176913:399;;;176970:15;;176960:29;;-1:-1:-1;;;;;176970:15:0;176987:1;176960:9;:29::i;:::-;177006:13;177017:1;177006:10;:13::i;:::-;177057:17;;:45;;-1:-1:-1;;;177057:45:0;;;;;13113:25:1;;;-1:-1:-1;;;;;177057:17:0;;;;:42;;13086:18:1;;177057:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;177036:66;;;;:::i;:::-;177131:15;;-1:-1:-1;;;;;177131:15:0;177119:28;;;;:11;:28;;;;;;;;:36;;177131:15;177119:36;;;;;;;;;;;;;;;;;177172:128;;;;;;;;;;;;177036:66;;-1:-1:-1;177172:128:0;;177153:1;;177172:128;;;;;;:12;:128::i;:::-;176940:3;;;;:::i;:::-;;;;176913:399;;49703:159;48719:13;:11;:13::i;:::-;-1:-1:-1;;;;;49792:22:0;::::1;49784:31;;;::::0;::::1;;49826:28;49845:8;49826:18;:28::i;12533:114::-:0;12625:14;;12533:114::o;12655:127::-;12744:19;;12762:1;12744:19;;;12655:127::o;1070:326::-;-1:-1:-1;;;;;1365:19:0;;:23;;;1070:326::o;42686:107::-;42768:16;42776:7;42768;:16::i;:::-;42760:25;;;;;41994:174;42069:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;42069:29:0;-1:-1:-1;;;;;42069:29:0;;;;;;;;:24;;42123:23;42069:24;42123:14;:23::i;:::-;-1:-1:-1;;;;;42114:46:0;;;;;;;;;;;41994:174;;:::o;174787:340::-;174856:16;;174838:15;:34;174834:286;;;174889:18;;;;;;;;;-1:-1:-1;;;;;174889:18:0;-1:-1:-1;;;;;174889:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;174931:18;;;;;;;;;-1:-1:-1;;;;;174931:18:0;-1:-1:-1;;;;;174931:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;174975:20;;;;;;;;;-1:-1:-1;;;;;174975:20:0;-1:-1:-1;;;;;174975:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;175019:20;;;;;;;;;-1:-1:-1;;;;;175019:20:0;-1:-1:-1;;;;;175019:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;175102:6;;175084:15;:24;;;;:::i;:::-;175065:16;:43;174787:340::o;174303:476::-;-1:-1:-1;;;;;174373:20:0;;;;;;:12;:20;;;;;;;;174369:193;;;-1:-1:-1;;;;;174428:30:0;;;;;;:22;:30;;;;;;174410:14;:48;;174428:30;;174410:14;;:48;;174428:30;;174410:48;:::i;:::-;;;;-1:-1:-1;;;;;;;174473:30:0;;174506:1;174473:30;;;:22;:30;;;;;;;;:34;;;174522:12;:20;;;;;:28;;-1:-1:-1;;174522:28:0;;;174369:193;174578:4;;:23;;-1:-1:-1;;;174578:23:0;;-1:-1:-1;;;;;174578:4:0;;;;:15;;:23;;174594:6;;174578:23;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;174574:198;;;174636:17;174646:6;174636:9;:17::i;:::-;174618:14;;:35;;;;;;;:::i;:::-;;;;-1:-1:-1;174701:17:0;;-1:-1:-1;174711:6:0;174701:9;:17::i;:::-;-1:-1:-1;;;;;174668:30:0;;;;;;:22;:30;;;;;;;;:50;;;;174733:12;:20;;;:27;;-1:-1:-1;;174733:27:0;174756:4;174733:27;;;174303:476;:::o;36021:315::-;36139:4;36156:13;36172:23;36187:7;36172:14;:23::i;:::-;36156:39;;36225:5;-1:-1:-1;;;;;36214:16:0;:7;-1:-1:-1;;;;;36214:16:0;;:65;;;;36247:32;36264:5;36271:7;36247:16;:32::i;:::-;36214:113;;;;36320:7;-1:-1:-1;;;;;36296:31:0;:20;36308:7;36296:11;:20::i;:::-;-1:-1:-1;;;;;36296:31:0;;36214:113;36206:122;36021:315;-1:-1:-1;;;;36021:315:0:o;40629:1246::-;40788:4;-1:-1:-1;;;;;40761:31:0;:23;40776:7;40761:14;:23::i;:::-;-1:-1:-1;;;;;40761:31:0;;40753:40;;;;;;-1:-1:-1;;;;;40812:16:0;;40804:25;;;;;;41011:4;-1:-1:-1;;;;;40984:31:0;:23;40999:7;40984:14;:23::i;:::-;-1:-1:-1;;;;;40984:31:0;;40976:40;;;;;;41088:24;;;;:15;:24;;;;;41081:31;;-1:-1:-1;;;;;;41081:31:0;;;41566:41;41104:7;41602:4;41566:26;:41::i;:::-;-1:-1:-1;;;;;41622:15:0;;;;;;:9;:15;;;;;:20;;-1:-1:-1;;41622:20:0;;;41659:36;41683:7;41692:2;41659:23;:36::i;:::-;-1:-1:-1;;;;;41710:13:0;;;;;;;:9;:13;;;;;;;;:18;;41727:1;41710:18;;;41750:16;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;41750:21:0;;;;;41789:27;41758:7;;41789:27;;;-1:-1:-1;;;;;;;;;;;41789:27:0;;32117:207;32047:277;;:::o;175808:808::-;175932:13;;175980:629;175991:1;175987;:5;175980:629;;;176013:7;176009:50;;;176022:37;176036:1;176039:7;176048:10;176022:13;:37::i;:::-;176084:19;176092:10;176084:7;:19::i;:::-;-1:-1:-1;;;;;176120:30:0;;;;;;:23;:30;;;;;:40;;176076:27;;-1:-1:-1;157184:7:0;;176120:30;;;:40;;157184:7;;176120:40;:::i;:::-;;;;-1:-1:-1;;176175:40:0;;;;:28;:40;;;;;:50;;157184:7;;176175:40;:50;;157184:7;;176175:50;:::i;:::-;;;;;;;;157184:7;176240:28;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;176293:4:0;;:28;;-1:-1:-1;;;176293:28:0;;-1:-1:-1;;;;;176293:4:0;;;;:13;;:28;;176307:5;;157184:7;;176293:28;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;176488:15;176464:5;-1:-1:-1;;;;;176371:147:0;;176410:10;157184:7;176371:147;;;;;;;:::i;:::-;;;;;;;;176548:29;;;;:17;:29;;;;;;;;176594:3;;;;:::i;:::-;;;;175980:629;;;175921:695;;175808:808;;;:::o;35296:117::-;35362:7;35389:16;;;:7;:16;;;;;;-1:-1:-1;;;;;35389:16:0;;35296:117::o;36678:110::-;36754:26;36764:2;36768:7;36754:26;;;;;;;;;;;;:9;:26::i;47608:192::-;47733:16;47741:7;47733;:16::i;:::-;47725:25;;;;;;47761:19;;;;:10;:19;;;;;;;;:31;;;;;;;;:::i;48998:96::-;26114:10;49062:7;:5;:7::i;:::-;-1:-1:-1;;;;;49062:23:0;;49054:32;;;;;50022:191;50115:6;;;-1:-1:-1;;;;;50132:17:0;;;-1:-1:-1;;;;;;50132:17:0;;;;;;;50165:40;;50115:6;;;50132:17;50115:6;;50165:40;;50096:16;;50165:40;50085:128;50022:191;:::o;164020:1879::-;164123:17;;:37;;-1:-1:-1;;;164123:37:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164123:17:0;;;;:30;;13086:18:1;;164123:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;164123:37:0;;;;;;;;;;;;:::i;:::-;164101:19;;;;:12;:19;;;;;;;;:59;;;;:19;;:59;;;;;;:::i;:::-;-1:-1:-1;164200:17:0;;:68;;-1:-1:-1;;;164200:68:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164200:17:0;;;;:37;;13086:18:1;;164200:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;164200:68:0;;;;;;;;;;;;:::i;:::-;164171:26;;;;:19;:26;;;;;;;;:97;;;;:26;;:97;;;;;;:::i;:::-;-1:-1:-1;164311:17:0;;:61;;-1:-1:-1;;;164311:61:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164311:17:0;;;;:54;;13086:18:1;;164311:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;164311:61:0;;;;;;;;;;;;:::i;:::-;164279:29;;;;:22;:29;;;;;;;;:93;;;;:29;;:93;;;;;;:::i;:::-;-1:-1:-1;164418:17:0;;:64;;-1:-1:-1;;;164418:64:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164418:17:0;;;;:57;;13086:18:1;;164418:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;164383:32;;;;:25;:32;;;;;;;:99;;;;164520:17;;:42;;-1:-1:-1;;;164520:42:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164520:17:0;;;;:35;;13086:18:1;;164520:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;164520:42:0;;;;;;;;;;;;:::i;:::-;164493:24;;;;:17;:24;;;;;;;;:69;;;;:24;;:69;;;;;;:::i;:::-;-1:-1:-1;164600:17:0;;:42;;-1:-1:-1;;;164600:42:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164600:17:0;;;;:35;;13086:18:1;;164600:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;164573:24;;;;:17;:24;;;;;;;:69;;;;164720:17;;:71;;-1:-1:-1;;;164720:71:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164720:17:0;;;;:64;;13086:18:1;;164720:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;164678:39;;;;:32;:39;;;;;;;:113;;;;164845:17;;:72;;-1:-1:-1;;;164845:72:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164845:17:0;;;;:65;;13086:18:1;;164845:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;164802:40;;;;:33;:40;;;;;;;:115;;;;164970:17;;:71;;-1:-1:-1;;;164970:71:0;;;;;13113:25:1;;;-1:-1:-1;;;;;164970:17:0;;;;:64;;13086:18:1;;164970:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;164928:39;;;;:32;:39;;;;;;;:113;;;;165093:17;;:70;;-1:-1:-1;;;165093:70:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165093:17:0;;;;:63;;13086:18:1;;165093:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165052:38;;;;:31;:38;;;;;;;:111;;;;165215:17;;:70;;-1:-1:-1;;;165215:70:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165215:17:0;;;;:63;;13086:18:1;;165215:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165174:38;;;;:31;:38;;;;;;;;;:111;;;;165336:17;;:69;;-1:-1:-1;;;165336:69:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165336:17:0;;;;:62;;13086:18:1;165336:69:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165296:37;;;;:30;:37;;;;;;;:109;;;;165458:17;;:71;;-1:-1:-1;;;165458:71:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165458:17:0;;;;:64;;13086:18:1;;165458:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165416:39;;;;:32;:39;;;;;;;:113;;;;165582:17;;:71;;-1:-1:-1;;;165582:71:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165582:17:0;;;;:64;;13086:18:1;;165582:71:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165540:39;;;;:32;:39;;;;;;;:113;;;;165705:17;;:70;;-1:-1:-1;;;165705:70:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165705:17:0;;;;:63;;13086:18:1;;165705:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165664:38;;;;:31;:38;;;;;;;:111;;;;165825:17;;:66;;-1:-1:-1;;;165825:66:0;;;;;13113:25:1;;;-1:-1:-1;;;;;165825:17:0;;;;:59;;13086:18:1;;165825:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165788:34;;;;:27;:34;;;;;;:103;164020:1879::o;42311:286::-;42466:8;-1:-1:-1;;;;;42457:17:0;:5;-1:-1:-1;;;;;42457:17:0;;;42449:26;;;;;;-1:-1:-1;;;;;42486:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;42486:46:0;;;;;;;;;;42548:41;;11987::1;;;42548::0;;11960:18:1;42548:41:0;;;;;;;42311:286;;;:::o;34923:259::-;35079:28;35089:4;35095:2;35099:7;35079:9;:28::i;:::-;35126:47;35149:4;35155:2;35159:7;35168:4;35126:22;:47::i;:::-;35118:56;;;;;46812:640;46901:13;46927:23;46942:7;46927:14;:23::i;:::-;46963;46989:19;;;:10;:19;;;;;46963:45;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47019:18;47040:10;31968:9;;;;;;;;;-1:-1:-1;31968:9:0;;;31891:94;47040:10;47019:31;;47132:4;47126:18;47148:1;47126:23;47122:72;;;-1:-1:-1;47173:9:0;46812:640;-1:-1:-1;;46812:640:0:o;47122:72::-;47298:23;;:27;47294:108;;47373:4;47379:9;47356:33;;;;;;;;;:::i;:::-;;;;;;;;;;;;;47342:48;;;;46812:640;;;:::o;47294:108::-;47421:23;47436:7;47421:14;:23::i;35726:128::-;35791:4;;35815:17;35824:7;35815:8;:17::i;:::-;-1:-1:-1;;;;;35815:31:0;;;;35726:128;-1:-1:-1;;35726:128:0:o;39783:509::-;39896:9;39922:45;-1:-1:-1;;;;;39929:19:0;;;;;;:11;:19;;;;;:22;;39955:7;;39929:19;39949:1;;39929:22;;;;;;:::i;:::-;;;;;;;;;:33;39922:45;;39964:3;;;;:::i;:::-;;;;39922:45;;;-1:-1:-1;;;;;39993:17:0;;;;;;:9;:17;;;;;;:21;;40013:1;;39993:21;:::i;:::-;39988:1;:27;39980:120;;;-1:-1:-1;;;;;40062:19:0;;;;;;:11;:19;;;;;40082:5;:1;40086;40082:5;:::i;:::-;40062:26;;;;;;;;:::i;:::-;;;;;;;;;40037:11;:19;40049:6;-1:-1:-1;;;;;40037:19:0;-1:-1:-1;;;;;40037:19:0;;;;;;;;;;;;40057:1;40037:22;;;;;;;;:::i;:::-;;;;;;;;;;:51;40017:3;;;;:::i;:::-;;;;39980:120;;;-1:-1:-1;;;;;40112:19:0;;;;;;:11;:19;;;;;:25;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;40112:25:0;;;;;;;;;;;;-1:-1:-1;;;;;40154:21:0;;;;:13;:21;;;;;;:32;;40150:121;;;-1:-1:-1;;;;;40237:19:0;;;;;;:11;:19;;;;;:22;;:19;;;:22;;;;:::i;:::-;;;;;;;;;;;;;-1:-1:-1;;;;;40213:21:0;;;;:13;:21;;;;;;;:46;39885:407;39783:509;;:::o;39539:236::-;-1:-1:-1;;;;;39624:19:0;;;;;;:11;:19;;;;;;;;:33;;;;;;;;;;;;;;;;;39672:21;;;:13;:21;;;;39668:100;;-1:-1:-1;;;;;39725:21:0;;;;;:13;:21;;;;;:31;39539:236::o;177327:3266::-;177414:6;177410:344;;177437:37;;;;:32;:37;;;;;:39;;;;;;:::i;:::-;;;;-1:-1:-1;;177491:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;177616:31:0;;;;:26;:31;;;;;;;:45;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;177410:344::-;177770:1;177775;177770:6;177766:348;;;177793:38;;;;:33;:38;;;;;:40;;;;;;:::i;:::-;;;;-1:-1:-1;;177848:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;177974:32:0;;;;:27;:32;;;;;;;:46;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;177766:348::-;178130:1;178135;178130:6;178126:344;;;178153:37;;;;:32;:37;;;;;:39;;;;;;:::i;:::-;;;;-1:-1:-1;;178207:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;178332:31:0;;;;:26;:31;;;;;;;:45;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;178126:344::-;178486:1;178491;178486:6;178482:340;;;178509:36;;;;:31;:36;;;;;:38;;;;;;:::i;:::-;;;;-1:-1:-1;;178562:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;178686:30:0;;;;:25;:30;;;;;;;:44;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;178482:340::-;178838:1;178843;178838:6;178834:340;;;178861:36;;;;:31;:36;;;;;:38;;;;;;:::i;:::-;;;;-1:-1:-1;;178914:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;179038:30:0;;;;:25;:30;;;;;;;:44;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;178834:340::-;179190:1;179195;179190:6;179186:336;;;179213:35;;;;:30;:35;;;;;:37;;;;;;:::i;:::-;;;;-1:-1:-1;;179265:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;179388:29:0;;;;:24;:29;;;;;;;:43;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;179186:336::-;179538:1;179543;179538:6;179534:344;;;179561:37;;;;:32;:37;;;;;:39;;;;;;:::i;:::-;;;;-1:-1:-1;;179615:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;179740:31:0;;;;:26;:31;;;;;;;:45;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;179534:344::-;179894:1;179899;179894:6;179890:344;;;179917:37;;;;:32;:37;;;;;:39;;;;;;:::i;:::-;;;;-1:-1:-1;;179971:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;180096:31:0;;;;:26;:31;;;;;;;:45;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;179890:344::-;180250:1;180255;180250:6;180246:340;;;180273:36;;;;:31;:36;;;;;:38;;;;;;:::i;:::-;;;;-1:-1:-1;;180326:32:0;;;;:27;:32;;;;;:34;;;;;;:::i;:::-;;;;-1:-1:-1;;180450:30:0;;;;:25;:30;;;;;;;:44;;;;;;;;;;;;;;-1:-1:-1;177327:3266:0:o;37015:228::-;37144:18;37150:2;37154:7;37144:5;:18::i;:::-;37181:53;37212:1;37216:2;37220:7;37229:4;37181:22;:53::i;:::-;37173:62;;;;;43357:934;43511:4;43532:15;:2;-1:-1:-1;;;;;43532:13:0;;:15::i;:::-;43528:756;;;43585:174;;-1:-1:-1;;;43585:174:0;;-1:-1:-1;;;;;43585:36:0;;;;;:174;;26114:10;;43679:4;;43706:7;;43736:4;;43585:174;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;43585:174:0;;;;;;;;-1:-1:-1;;43585:174:0;;;;;;;;;;;;:::i;:::-;;;43564:665;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;43942:13:0;;43938:276;;43985:8;;;43938:276;44164:6;44158:13;44149:6;44145:2;44141:15;44134:38;43564:665;-1:-1:-1;;;;;;43823:51:0;-1:-1:-1;;;43823:51:0;;-1:-1:-1;43816:58:0;;43528:756;-1:-1:-1;44268:4:0;43357:934;;;;;;:::o;31298:344::-;31387:13;31413:23;31428:7;31413:14;:23::i;:::-;31449:21;31473:10;31968:9;;;;;;;;;-1:-1:-1;31968:9:0;;;31891:94;31473:10;31449:34;;31538:1;31520:7;31514:21;:25;:120;;;;;;;;;;;;;;;;;31583:7;31592:18;:7;:16;:18::i;:::-;31566:45;;;;;;;;;:::i;:::-;;;;;;;;;;;;;31514:120;31494:140;31298:344;-1:-1:-1;;;31298:344:0:o;37579:836::-;-1:-1:-1;;;;;37659:16:0;;37651:25;;;;;;37696:16;37704:7;37696;:16::i;:::-;37695:17;37687:26;;;;;;37870:16;37878:7;37870;:16::i;:::-;37869:17;37861:26;;;;;;-1:-1:-1;;;;;38236:13:0;;;;;;:9;:13;;;;;;;;:18;;38253:1;38236:18;;;38278:16;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;38278:21:0;;;;;38317:33;38286:7;;38236:13;;-1:-1:-1;;;;;;;;;;;38317:33:0;38236:13;;38317:33;163663:349;;:::o;10203:716::-;10259:13;10310:14;10327:17;10338:5;10327:10;:17::i;:::-;10347:1;10327:21;10310:38;;10363:20;10397:6;-1:-1:-1;;;;;10386:18:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10386:18:0;-1:-1:-1;10363:41:0;-1:-1:-1;10528:28:0;;;10544:2;10528:28;10585:288;-1:-1:-1;;10617:5:0;-1:-1:-1;;;10754:2:0;10743:14;;10738:30;10617:5;10725:44;10815:2;10806:11;;;-1:-1:-1;10840:10:0;10836:21;;10852:5;;10836:21;10585:288;;;-1:-1:-1;10894:6:0;10203:716;-1:-1:-1;;;10203:716:0:o;23149:948::-;23202:7;;-1:-1:-1;;;23280:17:0;;23276:106;;-1:-1:-1;;;23318:17:0;;;-1:-1:-1;23364:2:0;23354:12;23276:106;-1:-1:-1;;;23400:5:0;:17;23396:106;;-1:-1:-1;;;23438:17:0;;;-1:-1:-1;23484:2:0;23474:12;23396:106;23529:8;23520:5;:17;23516:106;;23567:8;23558:17;;;-1:-1:-1;23604:2:0;23594:12;23516:106;23649:7;23640:5;:16;23636:103;;23686:7;23677:16;;;-1:-1:-1;23722:1:0;23712:11;23636:103;23766:7;23757:5;:16;23753:103;;23803:7;23794:16;;;-1:-1:-1;23839:1:0;23829:11;23753:103;23883:7;23874:5;:16;23870:103;;23920:7;23911:16;;;-1:-1:-1;23956:1:0;23946:11;23870:103;24000:7;23991:5;:16;23987:68;;24038:1;24028:11;24083:6;23149:948;-1:-1:-1;;23149:948:0:o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:336:1;78:5;107:52;123:35;151:6;123:35;:::i;:::-;107:52;:::i;:::-;98:61;;182:6;175:5;168:21;222:3;213:6;208:3;204:16;201:25;198:45;;;239:1;236;229:12;198:45;288:6;283:3;276:4;269:5;265:16;252:43;342:1;335:4;326:6;319:5;315:18;311:29;304:40;14:336;;;;;:::o;355:221::-;398:5;451:3;444:4;436:6;432:17;428:27;418:55;;469:1;466;459:12;418:55;491:79;566:3;557:6;544:20;537:4;529:6;525:17;491:79;:::i;581:247::-;640:6;693:2;681:9;672:7;668:23;664:32;661:52;;;709:1;706;699:12;661:52;748:9;735:23;767:31;792:5;767:31;:::i;833:251::-;903:6;956:2;944:9;935:7;931:23;927:32;924:52;;;972:1;969;962:12;924:52;1004:9;998:16;1023:31;1048:5;1023:31;:::i;1089:388::-;1157:6;1165;1218:2;1206:9;1197:7;1193:23;1189:32;1186:52;;;1234:1;1231;1224:12;1186:52;1273:9;1260:23;1292:31;1317:5;1292:31;:::i;:::-;1342:5;-1:-1:-1;1399:2:1;1384:18;;1371:32;1412:33;1371:32;1412:33;:::i;:::-;1464:7;1454:17;;;1089:388;;;;;:::o;1482:456::-;1559:6;1567;1575;1628:2;1616:9;1607:7;1603:23;1599:32;1596:52;;;1644:1;1641;1634:12;1596:52;1683:9;1670:23;1702:31;1727:5;1702:31;:::i;:::-;1752:5;-1:-1:-1;1809:2:1;1794:18;;1781:32;1822:33;1781:32;1822:33;:::i;:::-;1482:456;;1874:7;;-1:-1:-1;;;1928:2:1;1913:18;;;;1900:32;;1482:456::o;1943:794::-;2038:6;2046;2054;2062;2115:3;2103:9;2094:7;2090:23;2086:33;2083:53;;;2132:1;2129;2122:12;2083:53;2171:9;2158:23;2190:31;2215:5;2190:31;:::i;:::-;2240:5;-1:-1:-1;2297:2:1;2282:18;;2269:32;2310:33;2269:32;2310:33;:::i;:::-;2362:7;-1:-1:-1;2416:2:1;2401:18;;2388:32;;-1:-1:-1;2471:2:1;2456:18;;2443:32;-1:-1:-1;;;;;2487:30:1;;2484:50;;;2530:1;2527;2520:12;2484:50;2553:22;;2606:4;2598:13;;2594:27;-1:-1:-1;2584:55:1;;2635:1;2632;2625:12;2584:55;2658:73;2723:7;2718:2;2705:16;2700:2;2696;2692:11;2658:73;:::i;:::-;2648:83;;;1943:794;;;;;;;:::o;2742:382::-;2807:6;2815;2868:2;2856:9;2847:7;2843:23;2839:32;2836:52;;;2884:1;2881;2874:12;2836:52;2923:9;2910:23;2942:31;2967:5;2942:31;:::i;:::-;2992:5;-1:-1:-1;3049:2:1;3034:18;;3021:32;3062:30;3021:32;3062:30;:::i;3129:315::-;3197:6;3205;3258:2;3246:9;3237:7;3233:23;3229:32;3226:52;;;3274:1;3271;3264:12;3226:52;3313:9;3300:23;3332:31;3357:5;3332:31;:::i;:::-;3382:5;3434:2;3419:18;;;;3406:32;;-1:-1:-1;;;3129:315:1:o;3449:245::-;3516:6;3569:2;3557:9;3548:7;3544:23;3540:32;3537:52;;;3585:1;3582;3575:12;3537:52;3617:9;3611:16;3636:28;3658:5;3636:28;:::i;3699:245::-;3757:6;3810:2;3798:9;3789:7;3785:23;3781:32;3778:52;;;3826:1;3823;3816:12;3778:52;3865:9;3852:23;3884:30;3908:5;3884:30;:::i;3949:249::-;4018:6;4071:2;4059:9;4050:7;4046:23;4042:32;4039:52;;;4087:1;4084;4077:12;4039:52;4119:9;4113:16;4138:30;4162:5;4138:30;:::i;4474:735::-;4624:6;4632;4640;4648;4701:3;4689:9;4680:7;4676:23;4672:33;4669:53;;;4718:1;4715;4708:12;4669:53;4757:9;4744:23;4776:31;4801:5;4776:31;:::i;:::-;4826:5;-1:-1:-1;4883:2:1;4868:18;;4855:32;4896:33;4855:32;4896:33;:::i;:::-;4948:7;-1:-1:-1;5007:2:1;4992:18;;4979:32;5020:33;4979:32;5020:33;:::i;:::-;5072:7;-1:-1:-1;5131:2:1;5116:18;;5103:32;5144:33;5103:32;5144:33;:::i;:::-;4474:735;;;;-1:-1:-1;4474:735:1;;-1:-1:-1;;4474:735:1:o;5487:635::-;5567:6;5620:2;5608:9;5599:7;5595:23;5591:32;5588:52;;;5636:1;5633;5626:12;5588:52;5663:16;;-1:-1:-1;;;;;5691:30:1;;5688:50;;;5734:1;5731;5724:12;5688:50;5757:22;;5810:4;5802:13;;5798:27;-1:-1:-1;5788:55:1;;5839:1;5836;5829:12;5788:55;5868:2;5862:9;5893:48;5909:31;5937:2;5909:31;:::i;5893:48::-;5964:2;5957:5;5950:17;6004:7;5999:2;5994;5990;5986:11;5982:20;5979:33;5976:53;;;6025:1;6022;6015:12;5976:53;6038:54;6089:2;6084;6077:5;6073:14;6068:2;6064;6060:11;6038:54;:::i;:::-;6111:5;5487:635;-1:-1:-1;;;;;5487:635:1:o;6127:1283::-;6290:6;6298;6306;6314;6322;6330;6338;6391:3;6379:9;6370:7;6366:23;6362:33;6359:53;;;6408:1;6405;6398:12;6359:53;6435:23;;-1:-1:-1;;;;;6507:14:1;;;6504:34;;;6534:1;6531;6524:12;6504:34;6557:50;6599:7;6590:6;6579:9;6575:22;6557:50;:::i;:::-;6547:60;;6660:2;6649:9;6645:18;6632:32;6616:48;;6689:2;6679:8;6676:16;6673:36;;;6705:1;6702;6695:12;6673:36;6728:52;6772:7;6761:8;6750:9;6746:24;6728:52;:::i;:::-;6718:62;;6833:2;6822:9;6818:18;6805:32;6789:48;;6862:2;6852:8;6849:16;6846:36;;;6878:1;6875;6868:12;6846:36;6901:52;6945:7;6934:8;6923:9;6919:24;6901:52;:::i;:::-;6891:62;;7006:2;6995:9;6991:18;6978:32;6962:48;;7035:2;7025:8;7022:16;7019:36;;;7051:1;7048;7041:12;7019:36;7074:52;7118:7;7107:8;7096:9;7092:24;7074:52;:::i;:::-;7064:62;;7179:3;7168:9;7164:19;7151:33;7135:49;;7209:2;7199:8;7196:16;7193:36;;;7225:1;7222;7215:12;7193:36;;7248:52;7292:7;7281:8;7270:9;7266:24;7248:52;:::i;:::-;7238:62;;;7347:3;7336:9;7332:19;7319:33;7309:43;;7399:3;7388:9;7384:19;7371:33;7361:43;;6127:1283;;;;;;;;;;:::o;7415:812::-;7531:6;7539;7547;7555;7608:3;7596:9;7587:7;7583:23;7579:33;7576:53;;;7625:1;7622;7615:12;7576:53;7652:23;;-1:-1:-1;;;;;7724:14:1;;;7721:34;;;7751:1;7748;7741:12;7721:34;7774:50;7816:7;7807:6;7796:9;7792:22;7774:50;:::i;:::-;7764:60;;7877:2;7866:9;7862:18;7849:32;7833:48;;7906:2;7896:8;7893:16;7890:36;;;7922:1;7919;7912:12;7890:36;7945:52;7989:7;7978:8;7967:9;7963:24;7945:52;:::i;:::-;7935:62;;8050:2;8039:9;8035:18;8022:32;8006:48;;8079:2;8069:8;8066:16;8063:36;;;8095:1;8092;8085:12;8063:36;;8118:52;8162:7;8151:8;8140:9;8136:24;8118:52;:::i;:::-;7415:812;;;;-1:-1:-1;8108:62:1;;8217:2;8202:18;8189:32;;-1:-1:-1;;;7415:812:1:o;8232:180::-;8291:6;8344:2;8332:9;8323:7;8319:23;8315:32;8312:52;;;8360:1;8357;8350:12;8312:52;-1:-1:-1;8383:23:1;;8232:180;-1:-1:-1;8232:180:1:o;8417:184::-;8487:6;8540:2;8528:9;8519:7;8515:23;8511:32;8508:52;;;8556:1;8553;8546:12;8508:52;-1:-1:-1;8579:16:1;;8417:184;-1:-1:-1;8417:184:1:o;8606:248::-;8674:6;8682;8735:2;8723:9;8714:7;8710:23;8706:32;8703:52;;;8751:1;8748;8741:12;8703:52;-1:-1:-1;;8774:23:1;;;8844:2;8829:18;;;8816:32;;-1:-1:-1;8606:248:1:o;8859:257::-;8900:3;8938:5;8932:12;8965:6;8960:3;8953:19;8981:63;9037:6;9030:4;9025:3;9021:14;9014:4;9007:5;9003:16;8981:63;:::i;:::-;9098:2;9077:15;-1:-1:-1;;9073:29:1;9064:39;;;;9105:4;9060:50;;8859:257;-1:-1:-1;;8859:257:1:o;9121:276::-;9252:3;9290:6;9284:13;9306:53;9352:6;9347:3;9340:4;9332:6;9328:17;9306:53;:::i;:::-;9375:16;;;;;9121:276;-1:-1:-1;;9121:276:1:o;9402:470::-;9581:3;9619:6;9613:13;9635:53;9681:6;9676:3;9669:4;9661:6;9657:17;9635:53;:::i;:::-;9751:13;;9710:16;;;;9773:57;9751:13;9710:16;9807:4;9795:17;;9773:57;:::i;:::-;9846:20;;9402:470;-1:-1:-1;;;;9402:470:1:o;9877:203::-;-1:-1:-1;;;;;10041:32:1;;;;10023:51;;10011:2;9996:18;;9877:203::o;10085:375::-;-1:-1:-1;;;;;10343:15:1;;;10325:34;;10395:15;;;;10390:2;10375:18;;10368:43;10442:2;10427:18;;10420:34;;;;10275:2;10260:18;;10085:375::o;10465:488::-;-1:-1:-1;;;;;10734:15:1;;;10716:34;;10786:15;;10781:2;10766:18;;10759:43;10833:2;10818:18;;10811:34;;;10881:3;10876:2;10861:18;;10854:31;;;10659:4;;10902:45;;10927:19;;10919:6;10902:45;:::i;:::-;10894:53;10465:488;-1:-1:-1;;;;;;10465:488:1:o;10958:300::-;-1:-1:-1;;;;;11176:32:1;;;;11158:51;;11240:2;11225:18;;11218:34;11146:2;11131:18;;10958:300::o;13357:219::-;13506:2;13495:9;13488:21;13469:4;13526:44;13566:2;13555:9;13551:18;13543:6;13526:44;:::i;14171:248::-;14345:25;;;14401:2;14386:18;;14379:34;14333:2;14318:18;;14171:248::o;14424:275::-;14495:2;14489:9;14560:2;14541:13;;-1:-1:-1;;14537:27:1;14525:40;;-1:-1:-1;;;;;14580:34:1;;14616:22;;;14577:62;14574:88;;;14642:18;;:::i;:::-;14678:2;14671:22;14424:275;;-1:-1:-1;14424:275:1:o;14704:186::-;14752:4;-1:-1:-1;;;;;14774:30:1;;14771:56;;;14807:18;;:::i;:::-;-1:-1:-1;14873:2:1;14852:15;-1:-1:-1;;14848:29:1;14879:4;14844:40;;14704:186::o;14895:128::-;14935:3;14966:1;14962:6;14959:1;14956:13;14953:39;;;14972:18;;:::i;:::-;-1:-1:-1;15008:9:1;;14895:128::o;15028:125::-;15068:4;15096:1;15093;15090:8;15087:34;;;15101:18;;:::i;:::-;-1:-1:-1;15138:9:1;;15028:125::o;15158:258::-;15230:1;15240:113;15254:6;15251:1;15248:13;15240:113;;;15330:11;;;15324:18;15311:11;;;15304:39;15276:2;15269:10;15240:113;;;15371:6;15368:1;15365:13;15362:48;;;-1:-1:-1;;15406:1:1;15388:16;;15381:27;15158:258::o;15421:380::-;15500:1;15496:12;;;;15543;;;15564:61;;15618:4;15610:6;15606:17;15596:27;;15564:61;15671:2;15663:6;15660:14;15640:18;15637:38;15634:161;;;15717:10;15712:3;15708:20;15705:1;15698:31;15752:4;15749:1;15742:15;15780:4;15777:1;15770:15;15634:161;;15421:380;;;:::o;15806:135::-;15845:3;-1:-1:-1;;15866:17:1;;15863:43;;;15886:18;;:::i;:::-;-1:-1:-1;15933:1:1;15922:13;;15806:135::o;15946:127::-;16007:10;16002:3;15998:20;15995:1;15988:31;16038:4;16035:1;16028:15;16062:4;16059:1;16052:15;16210:127;16271:10;16266:3;16262:20;16259:1;16252:31;16302:4;16299:1;16292:15;16326:4;16323:1;16316:15;16342:127;16403:10;16398:3;16394:20;16391:1;16384:31;16434:4;16431:1;16424:15;16458:4;16455:1;16448:15;16474:127;16535:10;16530:3;16526:20;16523:1;16516:31;16566:4;16563:1;16556:15;16590:4;16587:1;16580:15;16606:131;-1:-1:-1;;;;;16681:31:1;;16671:42;;16661:70;;16727:1;16724;16717:12;16742:118;16828:5;16821:13;16814:21;16807:5;16804:32;16794:60;;16850:1;16847;16840:12;16865:131;-1:-1:-1;;;;;;16939:32:1;;16929:43;;16919:71;;16986:1;16983;16976:12

Swarm Source

ipfs://f0db85a3c35611b4775d04f5137da082f4100840cb359a55c06f20ea969e65d5

Block Transaction Gas Used Reward
view all blocks collator

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.