ETH Price: $3,060.11 (+2.67%)
Gas: 1 Gwei

Token

Holdem Heroes (HEH)
 

Overview

Max Total Supply

270 HEH

Holders

40

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
16 HEH
0x3be51e47f76defe31aa61b048b102693f5bbec24
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
HoldemHeroes

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-04-20
*/

// SPDX-License-Identifier: MIT


pragma solidity >=0.8.9;

/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivFixedPointOverflow(uint256 prod1);

/// @notice Emitted when the result overflows uint256.
error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);

/// @notice Emitted when one of the inputs is type(int256).min.
error PRBMath__MulDivSignedInputTooSmall();

/// @notice Emitted when the intermediary absolute result overflows int256.
error PRBMath__MulDivSignedOverflow(uint256 rAbs);

/// @notice Emitted when the input is MIN_SD59x18.
error PRBMathSD59x18__AbsInputTooSmall();

/// @notice Emitted when ceiling a number overflows SD59x18.
error PRBMathSD59x18__CeilOverflow(int256 x);

/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__DivInputTooSmall();

/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.
error PRBMathSD59x18__DivOverflow(uint256 rAbs);

/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathSD59x18__ExpInputTooBig(int256 x);

/// @notice Emitted when the input is greater than 192.
error PRBMathSD59x18__Exp2InputTooBig(int256 x);

/// @notice Emitted when flooring a number underflows SD59x18.
error PRBMathSD59x18__FloorUnderflow(int256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.
error PRBMathSD59x18__FromIntOverflow(int256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.
error PRBMathSD59x18__FromIntUnderflow(int256 x);

/// @notice Emitted when the product of the inputs is negative.
error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);

/// @notice Emitted when multiplying the inputs overflows SD59x18.
error PRBMathSD59x18__GmOverflow(int256 x, int256 y);

/// @notice Emitted when the input is less than or equal to zero.
error PRBMathSD59x18__LogInputTooSmall(int256 x);

/// @notice Emitted when one of the inputs is MIN_SD59x18.
error PRBMathSD59x18__MulInputTooSmall();

/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__MulOverflow(uint256 rAbs);

/// @notice Emitted when the intermediary absolute result overflows SD59x18.
error PRBMathSD59x18__PowuOverflow(uint256 rAbs);

/// @notice Emitted when the input is negative.
error PRBMathSD59x18__SqrtNegativeInput(int256 x);

/// @notice Emitted when the calculating the square root overflows SD59x18.
error PRBMathSD59x18__SqrtOverflow(int256 x);

/// @notice Emitted when addition overflows UD60x18.
error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);

/// @notice Emitted when ceiling a number overflows UD60x18.
error PRBMathUD60x18__CeilOverflow(uint256 x);

/// @notice Emitted when the input is greater than 133.084258667509499441.
error PRBMathUD60x18__ExpInputTooBig(uint256 x);

/// @notice Emitted when the input is greater than 192.
error PRBMathUD60x18__Exp2InputTooBig(uint256 x);

/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.
error PRBMathUD60x18__FromUintOverflow(uint256 x);

/// @notice Emitted when multiplying the inputs overflows UD60x18.
error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);

/// @notice Emitted when the input is less than 1.
error PRBMathUD60x18__LogInputTooSmall(uint256 x);

/// @notice Emitted when the calculating the square root overflows UD60x18.
error PRBMathUD60x18__SqrtOverflow(uint256 x);

/// @notice Emitted when subtraction underflows UD60x18.
error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);


/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library
/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point
/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.
library PRBMath {
    /// STRUCTS ///

    struct SD59x18 {
        int256 value;
    }

    struct UD60x18 {
        uint256 value;
    }

    /// STORAGE ///

    /// @dev How many trailing decimals can be represented.
    uint256 internal constant SCALE = 1e18;

    /// @dev Largest power of two divisor of SCALE.
    uint256 internal constant SCALE_LPOTD = 262144;

    /// @dev SCALE inverted mod 2^256.
    uint256 internal constant SCALE_INVERSE =
        78156646155174841979727994598816262306175212592076161876661_508869554232690281;

    /// FUNCTIONS ///

    /// @notice Calculates the binary exponent of x using the binary fraction method.
    /// @dev Has to use 192.64-bit fixed-point numbers.
    /// See https://ethereum.stackexchange.com/a/96594/24693.
    /// @param x The exponent as an unsigned 192.64-bit fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function exp2(uint256 x) internal pure returns (uint256 result) {
        unchecked {
            // Start from 0.5 in the 192.64-bit fixed-point format.
            result = 0x800000000000000000000000000000000000000000000000;

            // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows
            // because the initial result is 2^191 and all magic factors are less than 2^65.
            if (x & 0x8000000000000000 > 0) {
                result = (result * 0x16A09E667F3BCC909) >> 64;
            }
            if (x & 0x4000000000000000 > 0) {
                result = (result * 0x1306FE0A31B7152DF) >> 64;
            }
            if (x & 0x2000000000000000 > 0) {
                result = (result * 0x1172B83C7D517ADCE) >> 64;
            }
            if (x & 0x1000000000000000 > 0) {
                result = (result * 0x10B5586CF9890F62A) >> 64;
            }
            if (x & 0x800000000000000 > 0) {
                result = (result * 0x1059B0D31585743AE) >> 64;
            }
            if (x & 0x400000000000000 > 0) {
                result = (result * 0x102C9A3E778060EE7) >> 64;
            }
            if (x & 0x200000000000000 > 0) {
                result = (result * 0x10163DA9FB33356D8) >> 64;
            }
            if (x & 0x100000000000000 > 0) {
                result = (result * 0x100B1AFA5ABCBED61) >> 64;
            }
            if (x & 0x80000000000000 > 0) {
                result = (result * 0x10058C86DA1C09EA2) >> 64;
            }
            if (x & 0x40000000000000 > 0) {
                result = (result * 0x1002C605E2E8CEC50) >> 64;
            }
            if (x & 0x20000000000000 > 0) {
                result = (result * 0x100162F3904051FA1) >> 64;
            }
            if (x & 0x10000000000000 > 0) {
                result = (result * 0x1000B175EFFDC76BA) >> 64;
            }
            if (x & 0x8000000000000 > 0) {
                result = (result * 0x100058BA01FB9F96D) >> 64;
            }
            if (x & 0x4000000000000 > 0) {
                result = (result * 0x10002C5CC37DA9492) >> 64;
            }
            if (x & 0x2000000000000 > 0) {
                result = (result * 0x1000162E525EE0547) >> 64;
            }
            if (x & 0x1000000000000 > 0) {
                result = (result * 0x10000B17255775C04) >> 64;
            }
            if (x & 0x800000000000 > 0) {
                result = (result * 0x1000058B91B5BC9AE) >> 64;
            }
            if (x & 0x400000000000 > 0) {
                result = (result * 0x100002C5C89D5EC6D) >> 64;
            }
            if (x & 0x200000000000 > 0) {
                result = (result * 0x10000162E43F4F831) >> 64;
            }
            if (x & 0x100000000000 > 0) {
                result = (result * 0x100000B1721BCFC9A) >> 64;
            }
            if (x & 0x80000000000 > 0) {
                result = (result * 0x10000058B90CF1E6E) >> 64;
            }
            if (x & 0x40000000000 > 0) {
                result = (result * 0x1000002C5C863B73F) >> 64;
            }
            if (x & 0x20000000000 > 0) {
                result = (result * 0x100000162E430E5A2) >> 64;
            }
            if (x & 0x10000000000 > 0) {
                result = (result * 0x1000000B172183551) >> 64;
            }
            if (x & 0x8000000000 > 0) {
                result = (result * 0x100000058B90C0B49) >> 64;
            }
            if (x & 0x4000000000 > 0) {
                result = (result * 0x10000002C5C8601CC) >> 64;
            }
            if (x & 0x2000000000 > 0) {
                result = (result * 0x1000000162E42FFF0) >> 64;
            }
            if (x & 0x1000000000 > 0) {
                result = (result * 0x10000000B17217FBB) >> 64;
            }
            if (x & 0x800000000 > 0) {
                result = (result * 0x1000000058B90BFCE) >> 64;
            }
            if (x & 0x400000000 > 0) {
                result = (result * 0x100000002C5C85FE3) >> 64;
            }
            if (x & 0x200000000 > 0) {
                result = (result * 0x10000000162E42FF1) >> 64;
            }
            if (x & 0x100000000 > 0) {
                result = (result * 0x100000000B17217F8) >> 64;
            }
            if (x & 0x80000000 > 0) {
                result = (result * 0x10000000058B90BFC) >> 64;
            }
            if (x & 0x40000000 > 0) {
                result = (result * 0x1000000002C5C85FE) >> 64;
            }
            if (x & 0x20000000 > 0) {
                result = (result * 0x100000000162E42FF) >> 64;
            }
            if (x & 0x10000000 > 0) {
                result = (result * 0x1000000000B17217F) >> 64;
            }
            if (x & 0x8000000 > 0) {
                result = (result * 0x100000000058B90C0) >> 64;
            }
            if (x & 0x4000000 > 0) {
                result = (result * 0x10000000002C5C860) >> 64;
            }
            if (x & 0x2000000 > 0) {
                result = (result * 0x1000000000162E430) >> 64;
            }
            if (x & 0x1000000 > 0) {
                result = (result * 0x10000000000B17218) >> 64;
            }
            if (x & 0x800000 > 0) {
                result = (result * 0x1000000000058B90C) >> 64;
            }
            if (x & 0x400000 > 0) {
                result = (result * 0x100000000002C5C86) >> 64;
            }
            if (x & 0x200000 > 0) {
                result = (result * 0x10000000000162E43) >> 64;
            }
            if (x & 0x100000 > 0) {
                result = (result * 0x100000000000B1721) >> 64;
            }
            if (x & 0x80000 > 0) {
                result = (result * 0x10000000000058B91) >> 64;
            }
            if (x & 0x40000 > 0) {
                result = (result * 0x1000000000002C5C8) >> 64;
            }
            if (x & 0x20000 > 0) {
                result = (result * 0x100000000000162E4) >> 64;
            }
            if (x & 0x10000 > 0) {
                result = (result * 0x1000000000000B172) >> 64;
            }
            if (x & 0x8000 > 0) {
                result = (result * 0x100000000000058B9) >> 64;
            }
            if (x & 0x4000 > 0) {
                result = (result * 0x10000000000002C5D) >> 64;
            }
            if (x & 0x2000 > 0) {
                result = (result * 0x1000000000000162E) >> 64;
            }
            if (x & 0x1000 > 0) {
                result = (result * 0x10000000000000B17) >> 64;
            }
            if (x & 0x800 > 0) {
                result = (result * 0x1000000000000058C) >> 64;
            }
            if (x & 0x400 > 0) {
                result = (result * 0x100000000000002C6) >> 64;
            }
            if (x & 0x200 > 0) {
                result = (result * 0x10000000000000163) >> 64;
            }
            if (x & 0x100 > 0) {
                result = (result * 0x100000000000000B1) >> 64;
            }
            if (x & 0x80 > 0) {
                result = (result * 0x10000000000000059) >> 64;
            }
            if (x & 0x40 > 0) {
                result = (result * 0x1000000000000002C) >> 64;
            }
            if (x & 0x20 > 0) {
                result = (result * 0x10000000000000016) >> 64;
            }
            if (x & 0x10 > 0) {
                result = (result * 0x1000000000000000B) >> 64;
            }
            if (x & 0x8 > 0) {
                result = (result * 0x10000000000000006) >> 64;
            }
            if (x & 0x4 > 0) {
                result = (result * 0x10000000000000003) >> 64;
            }
            if (x & 0x2 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }
            if (x & 0x1 > 0) {
                result = (result * 0x10000000000000001) >> 64;
            }

            // We're doing two things at the same time:
            //
            //   1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for
            //      the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191
            //      rather than 192.
            //   2. Convert the result to the unsigned 60.18-decimal fixed-point format.
            //
            // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n".
            result *= SCALE;
            result >>= (191 - (x >> 64));
        }
    }

    /// @notice Finds the zero-based index of the first one in the binary representation of x.
    /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set
    /// @param x The uint256 number for which to find the index of the most significant bit.
    /// @return msb The index of the most significant bit as an uint256.
    function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {
        if (x >= 2**128) {
            x >>= 128;
            msb += 128;
        }
        if (x >= 2**64) {
            x >>= 64;
            msb += 64;
        }
        if (x >= 2**32) {
            x >>= 32;
            msb += 32;
        }
        if (x >= 2**16) {
            x >>= 16;
            msb += 16;
        }
        if (x >= 2**8) {
            x >>= 8;
            msb += 8;
        }
        if (x >= 2**4) {
            x >>= 4;
            msb += 4;
        }
        if (x >= 2**2) {
            x >>= 2;
            msb += 2;
        }
        if (x >= 2**1) {
            // No need to shift x any more.
            msb += 1;
        }
    }

    /// @notice Calculates floor(x*y÷denominator) with full precision.
    ///
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
    ///
    /// Requirements:
    /// - The denominator cannot be zero.
    /// - The result must fit within uint256.
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers.
    ///
    /// @param x The multiplicand as an uint256.
    /// @param y The multiplier as an uint256.
    /// @param denominator The divisor as an uint256.
    /// @return result The result as an uint256.
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        // 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) {
            unchecked {
                result = prod0 / denominator;
            }
            return result;
        }

        // Make sure the result is less than 2^256. Also prevents denominator == 0.
        if (prod1 >= denominator) {
            revert PRBMath__MulDivOverflow(prod1, denominator);
        }

        ///////////////////////////////////////////////
        // 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.
        unchecked {
            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 lpotdod = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by lpotdod.
                denominator := div(denominator, lpotdod)

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

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

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

            // 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 floor(x*y÷1e18) with full precision.
    ///
    /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the
    /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of
    /// being rounded to 1e-18.  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717.
    ///
    /// Requirements:
    /// - The result must fit within uint256.
    ///
    /// Caveats:
    /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works.
    /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:
    ///     1. x * y = type(uint256).max * SCALE
    ///     2. (x * y) % SCALE >= SCALE / 2
    ///
    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {
        uint256 prod0;
        uint256 prod1;
        assembly {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

        if (prod1 >= SCALE) {
            revert PRBMath__MulDivFixedPointOverflow(prod1);
        }

        uint256 remainder;
        uint256 roundUpUnit;
        assembly {
            remainder := mulmod(x, y, SCALE)
            roundUpUnit := gt(remainder, 499999999999999999)
        }

        if (prod1 == 0) {
            unchecked {
                result = (prod0 / SCALE) + roundUpUnit;
                return result;
            }
        }

        assembly {
            result := add(
                mul(
                    or(
                        div(sub(prod0, remainder), SCALE_LPOTD),
                        mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))
                    ),
                    SCALE_INVERSE
                ),
                roundUpUnit
            )
        }
    }

    /// @notice Calculates floor(x*y÷denominator) with full precision.
    ///
    /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately.
    ///
    /// Requirements:
    /// - None of the inputs can be type(int256).min.
    /// - The result must fit within int256.
    ///
    /// @param x The multiplicand as an int256.
    /// @param y The multiplier as an int256.
    /// @param denominator The divisor as an int256.
    /// @return result The result as an int256.
    function mulDivSigned(
        int256 x,
        int256 y,
        int256 denominator
    ) internal pure returns (int256 result) {
        if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
            revert PRBMath__MulDivSignedInputTooSmall();
        }

        // Get hold of the absolute values of x, y and the denominator.
        uint256 ax;
        uint256 ay;
        uint256 ad;
        unchecked {
            ax = x < 0 ? uint256(-x) : uint256(x);
            ay = y < 0 ? uint256(-y) : uint256(y);
            ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);
        }

        // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.
        uint256 rAbs = mulDiv(ax, ay, ad);
        if (rAbs > uint256(type(int256).max)) {
            revert PRBMath__MulDivSignedOverflow(rAbs);
        }

        // Get the signs of x, y and the denominator.
        uint256 sx;
        uint256 sy;
        uint256 sd;
        assembly {
            sx := sgt(x, sub(0, 1))
            sy := sgt(y, sub(0, 1))
            sd := sgt(denominator, sub(0, 1))
        }

        // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.
        // If yes, the result should be negative.
        result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);
    }

    /// @notice Calculates the square root of x, rounding down.
    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
    ///
    /// Caveats:
    /// - This function does not work with fixed-point numbers.
    ///
    /// @param x The uint256 number for which to calculate the square root.
    /// @return result The result as an uint256.
    function sqrt(uint256 x) internal pure returns (uint256 result) {
        if (x == 0) {
            return 0;
        }

        // Set the initial guess to the least power of two that is greater than or equal to sqrt(x).
        uint256 xAux = uint256(x);
        result = 1;
        if (xAux >= 0x100000000000000000000000000000000) {
            xAux >>= 128;
            result <<= 64;
        }
        if (xAux >= 0x10000000000000000) {
            xAux >>= 64;
            result <<= 32;
        }
        if (xAux >= 0x100000000) {
            xAux >>= 32;
            result <<= 16;
        }
        if (xAux >= 0x10000) {
            xAux >>= 16;
            result <<= 8;
        }
        if (xAux >= 0x100) {
            xAux >>= 8;
            result <<= 4;
        }
        if (xAux >= 0x10) {
            xAux >>= 4;
            result <<= 2;
        }
        if (xAux >= 0x8) {
            result <<= 1;
        }

        // The operations can never overflow because the result is max 2^127 when it enters this block.
        unchecked {
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1; // Seven iterations should be enough
            uint256 roundedDownResult = x / result;
            return result >= roundedDownResult ? roundedDownResult : result;
        }
    }
}


/// @title PRBMathSD59x18
/// @author Paul Razvan Berg
/// @notice Smart contract library for advanced fixed-point math that works with int256 numbers considered to have 18
/// trailing decimals. We call this number representation signed 59.18-decimal fixed-point, since the numbers can have
/// a sign and there can be up to 59 digits in the integer part and up to 18 decimals in the fractional part. The numbers
/// are bound by the minimum and the maximum values permitted by the Solidity type int256.
library PRBMathSD59x18 {
    /// @dev log2(e) as a signed 59.18-decimal fixed-point number.
    int256 internal constant LOG2_E = 1_442695040888963407;

    /// @dev Half the SCALE number.
    int256 internal constant HALF_SCALE = 5e17;

    /// @dev The maximum value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MAX_SD59x18 =
        57896044618658097711785492504343953926634992332820282019728_792003956564819967;

    /// @dev The maximum whole value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MAX_WHOLE_SD59x18 =
        57896044618658097711785492504343953926634992332820282019728_000000000000000000;

    /// @dev The minimum value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MIN_SD59x18 =
        -57896044618658097711785492504343953926634992332820282019728_792003956564819968;

    /// @dev The minimum whole value a signed 59.18-decimal fixed-point number can have.
    int256 internal constant MIN_WHOLE_SD59x18 =
        -57896044618658097711785492504343953926634992332820282019728_000000000000000000;

    /// @dev How many trailing decimals can be represented.
    int256 internal constant SCALE = 1e18;

    /// INTERNAL FUNCTIONS ///

    /// @notice Calculate the absolute value of x.
    ///
    /// @dev Requirements:
    /// - x must be greater than MIN_SD59x18.
    ///
    /// @param x The number to calculate the absolute value for.
    /// @param result The absolute value of x.
    function abs(int256 x) internal pure returns (int256 result) {
        unchecked {
            if (x == MIN_SD59x18) {
                revert PRBMathSD59x18__AbsInputTooSmall();
            }
            result = x < 0 ? -x : x;
        }
    }

    /// @notice Calculates the arithmetic average of x and y, rounding down.
    /// @param x The first operand as a signed 59.18-decimal fixed-point number.
    /// @param y The second operand as a signed 59.18-decimal fixed-point number.
    /// @return result The arithmetic average as a signed 59.18-decimal fixed-point number.
    function avg(int256 x, int256 y) internal pure returns (int256 result) {
        // The operations can never overflow.
        unchecked {
            int256 sum = (x >> 1) + (y >> 1);
            if (sum < 0) {
                // If at least one of x and y is odd, we add 1 to the result. This is because shifting negative numbers to the
                // right rounds down to infinity.
                assembly {
                    result := add(sum, and(or(x, y), 1))
                }
            } else {
                // If both x and y are odd, we add 1 to the result. This is because if both numbers are odd, the 0.5
                // remainder gets truncated twice.
                result = sum + (x & y & 1);
            }
        }
    }

    /// @notice Yields the least greatest signed 59.18 decimal fixed-point number greater than or equal to x.
    ///
    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
    ///
    /// Requirements:
    /// - x must be less than or equal to MAX_WHOLE_SD59x18.
    ///
    /// @param x The signed 59.18-decimal fixed-point number to ceil.
    /// @param result The least integer greater than or equal to x, as a signed 58.18-decimal fixed-point number.
    function ceil(int256 x) internal pure returns (int256 result) {
        if (x > MAX_WHOLE_SD59x18) {
            revert PRBMathSD59x18__CeilOverflow(x);
        }
        unchecked {
            int256 remainder = x % SCALE;
            if (remainder == 0) {
                result = x;
            } else {
                // Solidity uses C fmod style, which returns a modulus with the same sign as x.
                result = x - remainder;
                if (x > 0) {
                    result += SCALE;
                }
            }
        }
    }

    /// @notice Divides two signed 59.18-decimal fixed-point numbers, returning a new signed 59.18-decimal fixed-point number.
    ///
    /// @dev Variant of "mulDiv" that works with signed numbers. Works by computing the signs and the absolute values separately.
    ///
    /// Requirements:
    /// - All from "PRBMath.mulDiv".
    /// - None of the inputs can be MIN_SD59x18.
    /// - The denominator cannot be zero.
    /// - The result must fit within int256.
    ///
    /// Caveats:
    /// - All from "PRBMath.mulDiv".
    ///
    /// @param x The numerator as a signed 59.18-decimal fixed-point number.
    /// @param y The denominator as a signed 59.18-decimal fixed-point number.
    /// @param result The quotient as a signed 59.18-decimal fixed-point number.
    function div(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == MIN_SD59x18 || y == MIN_SD59x18) {
            revert PRBMathSD59x18__DivInputTooSmall();
        }

        // Get hold of the absolute values of x and y.
        uint256 ax;
        uint256 ay;
        unchecked {
            ax = x < 0 ? uint256(-x) : uint256(x);
            ay = y < 0 ? uint256(-y) : uint256(y);
        }

        // Compute the absolute value of (x*SCALE)÷y. The result must fit within int256.
        uint256 rAbs = PRBMath.mulDiv(ax, uint256(SCALE), ay);
        if (rAbs > uint256(MAX_SD59x18)) {
            revert PRBMathSD59x18__DivOverflow(rAbs);
        }

        // Get the signs of x and y.
        uint256 sx;
        uint256 sy;
        assembly {
            sx := sgt(x, sub(0, 1))
            sy := sgt(y, sub(0, 1))
        }

        // XOR over sx and sy. This is basically checking whether the inputs have the same sign. If yes, the result
        // should be positive. Otherwise, it should be negative.
        result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs);
    }

    /// @notice Returns Euler's number as a signed 59.18-decimal fixed-point number.
    /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).
    function e() internal pure returns (int256 result) {
        result = 2_718281828459045235;
    }

    /// @notice Calculates the natural exponent of x.
    ///
    /// @dev Based on the insight that e^x = 2^(x * log2(e)).
    ///
    /// Requirements:
    /// - All from "log2".
    /// - x must be less than 133.084258667509499441.
    ///
    /// Caveats:
    /// - All from "exp2".
    /// - For any x less than -41.446531673892822322, the result is zero.
    ///
    /// @param x The exponent as a signed 59.18-decimal fixed-point number.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function exp(int256 x) internal pure returns (int256 result) {
        // Without this check, the value passed to "exp2" would be less than -59.794705707972522261.
        if (x < -41_446531673892822322) {
            return 0;
        }

        // Without this check, the value passed to "exp2" would be greater than 192.
        if (x >= 133_084258667509499441) {
            revert PRBMathSD59x18__ExpInputTooBig(x);
        }

        // Do the fixed-point multiplication inline to save gas.
        unchecked {
            int256 doubleScaleProduct = x * LOG2_E;
            result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);
        }
    }

    /// @notice Calculates the binary exponent of x using the binary fraction method.
    ///
    /// @dev See https://ethereum.stackexchange.com/q/79903/24693.
    ///
    /// Requirements:
    /// - x must be 192 or less.
    /// - The result must fit within MAX_SD59x18.
    ///
    /// Caveats:
    /// - For any x less than -59.794705707972522261, the result is zero.
    ///
    /// @param x The exponent as a signed 59.18-decimal fixed-point number.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function exp2(int256 x) internal pure returns (int256 result) {
        // This works because 2^(-x) = 1/2^x.
        if (x < 0) {
            // 2^59.794705707972522262 is the maximum number whose inverse does not truncate down to zero.
            if (x < -59_794705707972522261) {
                return 0;
            }

            // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE.
            unchecked {
                result = 1e36 / exp2(-x);
            }
        } else {
            // 2^192 doesn't fit within the 192.64-bit format used internally in this function.
            if (x >= 192e18) {
                revert PRBMathSD59x18__Exp2InputTooBig(x);
            }

            unchecked {
                // Convert x to the 192.64-bit fixed-point format.
                uint256 x192x64 = (uint256(x) << 64) / uint256(SCALE);

                // Safe to convert the result to int256 directly because the maximum input allowed is 192.
                result = int256(PRBMath.exp2(x192x64));
            }
        }
    }

    /// @notice Yields the greatest signed 59.18 decimal fixed-point number less than or equal to x.
    ///
    /// @dev Optimized for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.
    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.
    ///
    /// Requirements:
    /// - x must be greater than or equal to MIN_WHOLE_SD59x18.
    ///
    /// @param x The signed 59.18-decimal fixed-point number to floor.
    /// @param result The greatest integer less than or equal to x, as a signed 58.18-decimal fixed-point number.
    function floor(int256 x) internal pure returns (int256 result) {
        if (x < MIN_WHOLE_SD59x18) {
            revert PRBMathSD59x18__FloorUnderflow(x);
        }
        unchecked {
            int256 remainder = x % SCALE;
            if (remainder == 0) {
                result = x;
            } else {
                // Solidity uses C fmod style, which returns a modulus with the same sign as x.
                result = x - remainder;
                if (x < 0) {
                    result -= SCALE;
                }
            }
        }
    }

    /// @notice Yields the excess beyond the floor of x for positive numbers and the part of the number to the right
    /// of the radix point for negative numbers.
    /// @dev Based on the odd function definition. https://en.wikipedia.org/wiki/Fractional_part
    /// @param x The signed 59.18-decimal fixed-point number to get the fractional part of.
    /// @param result The fractional part of x as a signed 59.18-decimal fixed-point number.
    function frac(int256 x) internal pure returns (int256 result) {
        unchecked {
            result = x % SCALE;
        }
    }

    /// @notice Converts a number from basic integer form to signed 59.18-decimal fixed-point representation.
    ///
    /// @dev Requirements:
    /// - x must be greater than or equal to MIN_SD59x18 divided by SCALE.
    /// - x must be less than or equal to MAX_SD59x18 divided by SCALE.
    ///
    /// @param x The basic integer to convert.
    /// @param result The same number in signed 59.18-decimal fixed-point representation.
    function fromInt(int256 x) internal pure returns (int256 result) {
        unchecked {
            if (x < MIN_SD59x18 / SCALE) {
                revert PRBMathSD59x18__FromIntUnderflow(x);
            }
            if (x > MAX_SD59x18 / SCALE) {
                revert PRBMathSD59x18__FromIntOverflow(x);
            }
            result = x * SCALE;
        }
    }

    /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.
    ///
    /// @dev Requirements:
    /// - x * y must fit within MAX_SD59x18, lest it overflows.
    /// - x * y cannot be negative.
    ///
    /// @param x The first operand as a signed 59.18-decimal fixed-point number.
    /// @param y The second operand as a signed 59.18-decimal fixed-point number.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function gm(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == 0) {
            return 0;
        }

        unchecked {
            // Checking for overflow this way is faster than letting Solidity do it.
            int256 xy = x * y;
            if (xy / x != y) {
                revert PRBMathSD59x18__GmOverflow(x, y);
            }

            // The product cannot be negative.
            if (xy < 0) {
                revert PRBMathSD59x18__GmNegativeProduct(x, y);
            }

            // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE
            // during multiplication. See the comments within the "sqrt" function.
            result = int256(PRBMath.sqrt(uint256(xy)));
        }
    }

    /// @notice Calculates 1 / x, rounding toward zero.
    ///
    /// @dev Requirements:
    /// - x cannot be zero.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the inverse.
    /// @return result The inverse as a signed 59.18-decimal fixed-point number.
    function inv(int256 x) internal pure returns (int256 result) {
        unchecked {
            // 1e36 is SCALE * SCALE.
            result = 1e36 / x;
        }
    }

    /// @notice Calculates the natural logarithm of x.
    ///
    /// @dev Based on the insight that ln(x) = log2(x) / log2(e).
    ///
    /// Requirements:
    /// - All from "log2".
    ///
    /// Caveats:
    /// - All from "log2".
    /// - This doesn't return exactly 1 for 2718281828459045235, for that we would need more fine-grained precision.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the natural logarithm.
    /// @return result The natural logarithm as a signed 59.18-decimal fixed-point number.
    function ln(int256 x) internal pure returns (int256 result) {
        // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)
        // can return is 195205294292027477728.
        unchecked {
            result = (log2(x) * SCALE) / LOG2_E;
        }
    }

    /// @notice Calculates the common logarithm of x.
    ///
    /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common
    /// logarithm based on the insight that log10(x) = log2(x) / log2(10).
    ///
    /// Requirements:
    /// - All from "log2".
    ///
    /// Caveats:
    /// - All from "log2".
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the common logarithm.
    /// @return result The common logarithm as a signed 59.18-decimal fixed-point number.
    function log10(int256 x) internal pure returns (int256 result) {
        if (x <= 0) {
            revert PRBMathSD59x18__LogInputTooSmall(x);
        }

        // Note that the "mul" in this block is the assembly mul operation, not the "mul" function defined in this contract.
        // prettier-ignore
        assembly {
            switch x
            case 1 { result := mul(SCALE, sub(0, 18)) }
            case 10 { result := mul(SCALE, sub(1, 18)) }
            case 100 { result := mul(SCALE, sub(2, 18)) }
            case 1000 { result := mul(SCALE, sub(3, 18)) }
            case 10000 { result := mul(SCALE, sub(4, 18)) }
            case 100000 { result := mul(SCALE, sub(5, 18)) }
            case 1000000 { result := mul(SCALE, sub(6, 18)) }
            case 10000000 { result := mul(SCALE, sub(7, 18)) }
            case 100000000 { result := mul(SCALE, sub(8, 18)) }
            case 1000000000 { result := mul(SCALE, sub(9, 18)) }
            case 10000000000 { result := mul(SCALE, sub(10, 18)) }
            case 100000000000 { result := mul(SCALE, sub(11, 18)) }
            case 1000000000000 { result := mul(SCALE, sub(12, 18)) }
            case 10000000000000 { result := mul(SCALE, sub(13, 18)) }
            case 100000000000000 { result := mul(SCALE, sub(14, 18)) }
            case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }
            case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }
            case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }
            case 1000000000000000000 { result := 0 }
            case 10000000000000000000 { result := SCALE }
            case 100000000000000000000 { result := mul(SCALE, 2) }
            case 1000000000000000000000 { result := mul(SCALE, 3) }
            case 10000000000000000000000 { result := mul(SCALE, 4) }
            case 100000000000000000000000 { result := mul(SCALE, 5) }
            case 1000000000000000000000000 { result := mul(SCALE, 6) }
            case 10000000000000000000000000 { result := mul(SCALE, 7) }
            case 100000000000000000000000000 { result := mul(SCALE, 8) }
            case 1000000000000000000000000000 { result := mul(SCALE, 9) }
            case 10000000000000000000000000000 { result := mul(SCALE, 10) }
            case 100000000000000000000000000000 { result := mul(SCALE, 11) }
            case 1000000000000000000000000000000 { result := mul(SCALE, 12) }
            case 10000000000000000000000000000000 { result := mul(SCALE, 13) }
            case 100000000000000000000000000000000 { result := mul(SCALE, 14) }
            case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }
            case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }
            case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }
            case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }
            case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }
            case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }
            case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }
            case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }
            case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }
            case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }
            case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }
            case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }
            case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }
            case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }
            case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }
            case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }
            case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }
            case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }
            case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }
            case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }
            case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }
            case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }
            case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }
            case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }
            case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }
            case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }
            case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }
            case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }
            case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }
            case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }
            case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }
            case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }
            case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }
            case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }
            case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }
            case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }
            case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }
            case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }
            case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }
            default {
                result := MAX_SD59x18
            }
        }

        if (result == MAX_SD59x18) {
            // Do the fixed-point division inline to save gas. The denominator is log2(10).
            unchecked {
                result = (log2(x) * SCALE) / 3_321928094887362347;
            }
        }
    }

    /// @notice Calculates the binary logarithm of x.
    ///
    /// @dev Based on the iterative approximation algorithm.
    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation
    ///
    /// Requirements:
    /// - x must be greater than zero.
    ///
    /// Caveats:
    /// - The results are not perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the binary logarithm.
    /// @return result The binary logarithm as a signed 59.18-decimal fixed-point number.
    function log2(int256 x) internal pure returns (int256 result) {
        if (x <= 0) {
            revert PRBMathSD59x18__LogInputTooSmall(x);
        }
        unchecked {
            // This works because log2(x) = -log2(1/x).
            int256 sign;
            if (x >= SCALE) {
                sign = 1;
            } else {
                sign = -1;
                // Do the fixed-point inversion inline to save gas. The numerator is SCALE * SCALE.
                assembly {
                    x := div(1000000000000000000000000000000000000, x)
                }
            }

            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
            uint256 n = PRBMath.mostSignificantBit(uint256(x / SCALE));

            // The integer part of the logarithm as a signed 59.18-decimal fixed-point number. The operation can't overflow
            // because n is maximum 255, SCALE is 1e18 and sign is either 1 or -1.
            result = int256(n) * SCALE;

            // This is y = x * 2^(-n).
            int256 y = x >> n;

            // If y = 1, the fractional part is zero.
            if (y == SCALE) {
                return result * sign;
            }

            // Calculate the fractional part via the iterative approximation.
            // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
            for (int256 delta = int256(HALF_SCALE); delta > 0; delta >>= 1) {
                y = (y * y) / SCALE;

                // Is y^2 > 2 and so in the range [2,4)?
                if (y >= 2 * SCALE) {
                    // Add the 2^(-m) factor to the logarithm.
                    result += delta;

                    // Corresponds to z/2 on Wikipedia.
                    y >>= 1;
                }
            }
            result *= sign;
        }
    }

    /// @notice Multiplies two signed 59.18-decimal fixed-point numbers together, returning a new signed 59.18-decimal
    /// fixed-point number.
    ///
    /// @dev Variant of "mulDiv" that works with signed numbers and employs constant folding, i.e. the denominator is
    /// always 1e18.
    ///
    /// Requirements:
    /// - All from "PRBMath.mulDivFixedPoint".
    /// - None of the inputs can be MIN_SD59x18
    /// - The result must fit within MAX_SD59x18.
    ///
    /// Caveats:
    /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works.
    ///
    /// @param x The multiplicand as a signed 59.18-decimal fixed-point number.
    /// @param y The multiplier as a signed 59.18-decimal fixed-point number.
    /// @return result The product as a signed 59.18-decimal fixed-point number.
    function mul(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == MIN_SD59x18 || y == MIN_SD59x18) {
            revert PRBMathSD59x18__MulInputTooSmall();
        }

        unchecked {
            uint256 ax;
            uint256 ay;
            ax = x < 0 ? uint256(-x) : uint256(x);
            ay = y < 0 ? uint256(-y) : uint256(y);

            uint256 rAbs = PRBMath.mulDivFixedPoint(ax, ay);
            if (rAbs > uint256(MAX_SD59x18)) {
                revert PRBMathSD59x18__MulOverflow(rAbs);
            }

            uint256 sx;
            uint256 sy;
            assembly {
                sx := sgt(x, sub(0, 1))
                sy := sgt(y, sub(0, 1))
            }
            result = sx ^ sy == 1 ? -int256(rAbs) : int256(rAbs);
        }
    }

    /// @notice Returns PI as a signed 59.18-decimal fixed-point number.
    function pi() internal pure returns (int256 result) {
        result = 3_141592653589793238;
    }

    /// @notice Raises x to the power of y.
    ///
    /// @dev Based on the insight that x^y = 2^(log2(x) * y).
    ///
    /// Requirements:
    /// - All from "exp2", "log2" and "mul".
    /// - z cannot be zero.
    ///
    /// Caveats:
    /// - All from "exp2", "log2" and "mul".
    /// - Assumes 0^0 is 1.
    ///
    /// @param x Number to raise to given power y, as a signed 59.18-decimal fixed-point number.
    /// @param y Exponent to raise x to, as a signed 59.18-decimal fixed-point number.
    /// @return result x raised to power y, as a signed 59.18-decimal fixed-point number.
    function pow(int256 x, int256 y) internal pure returns (int256 result) {
        if (x == 0) {
            result = y == 0 ? SCALE : int256(0);
        } else {
            result = exp2(mul(log2(x), y));
        }
    }

    /// @notice Raises x (signed 59.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the
    /// famous algorithm "exponentiation by squaring".
    ///
    /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring
    ///
    /// Requirements:
    /// - All from "abs" and "PRBMath.mulDivFixedPoint".
    /// - The result must fit within MAX_SD59x18.
    ///
    /// Caveats:
    /// - All from "PRBMath.mulDivFixedPoint".
    /// - Assumes 0^0 is 1.
    ///
    /// @param x The base as a signed 59.18-decimal fixed-point number.
    /// @param y The exponent as an uint256.
    /// @return result The result as a signed 59.18-decimal fixed-point number.
    function powu(int256 x, uint256 y) internal pure returns (int256 result) {
        uint256 xAbs = uint256(abs(x));

        // Calculate the first iteration of the loop in advance.
        uint256 rAbs = y & 1 > 0 ? xAbs : uint256(SCALE);

        // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
        uint256 yAux = y;
        for (yAux >>= 1; yAux > 0; yAux >>= 1) {
            xAbs = PRBMath.mulDivFixedPoint(xAbs, xAbs);

            // Equivalent to "y % 2 == 1" but faster.
            if (yAux & 1 > 0) {
                rAbs = PRBMath.mulDivFixedPoint(rAbs, xAbs);
            }
        }

        // The result must fit within the 59.18-decimal fixed-point representation.
        if (rAbs > uint256(MAX_SD59x18)) {
            revert PRBMathSD59x18__PowuOverflow(rAbs);
        }

        // Is the base negative and the exponent an odd number?
        bool isNegative = x < 0 && y & 1 == 1;
        result = isNegative ? -int256(rAbs) : int256(rAbs);
    }

    /// @notice Returns 1 as a signed 59.18-decimal fixed-point number.
    function scale() internal pure returns (int256 result) {
        result = SCALE;
    }

    /// @notice Calculates the square root of x, rounding down.
    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
    ///
    /// Requirements:
    /// - x cannot be negative.
    /// - x must be less than MAX_SD59x18 / SCALE.
    ///
    /// @param x The signed 59.18-decimal fixed-point number for which to calculate the square root.
    /// @return result The result as a signed 59.18-decimal fixed-point .
    function sqrt(int256 x) internal pure returns (int256 result) {
        unchecked {
            if (x < 0) {
                revert PRBMathSD59x18__SqrtNegativeInput(x);
            }
            if (x > MAX_SD59x18 / SCALE) {
                revert PRBMathSD59x18__SqrtOverflow(x);
            }
            // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two signed
            // 59.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).
            result = int256(PRBMath.sqrt(uint256(x * SCALE)));
        }
    }

    /// @notice Converts a signed 59.18-decimal fixed-point number to basic integer form, rounding down in the process.
    /// @param x The signed 59.18-decimal fixed-point number to convert.
    /// @return result The same number in basic integer form.
    function toInt(int256 x) internal pure returns (int256 result) {
        unchecked {
            result = x / SCALE;
        }
    }
}


/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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


/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

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

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

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

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

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

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}


/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library VORSafeMath {
     /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function saveDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function safeMod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }
}


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

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

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

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

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

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

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

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

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

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


interface IVORCoordinator {
    function getProviderAddress(bytes32 _keyHash) external view returns (address);
    function getProviderFee(bytes32 _keyHash) external view returns (uint96);
    function getProviderGranularFee(bytes32 _keyHash, address _consumer) external view returns (uint96);
    function randomnessRequest(bytes32 keyHash, uint256 consumerSeed, uint256 feePaid) external;
}


/**
 * @title VORRequestIDBase
 */
contract VORRequestIDBase {
    /**
     * @notice returns the seed which is actually input to the VOR coordinator
     *
     * @dev To prevent repetition of VOR output due to repetition of the
     * @dev user-supplied seed, that seed is combined in a hash with the
     * @dev user-specific nonce, and the address of the consuming contract. The
     * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in
     * @dev the final seed, but the nonce does protect against repetition in
     * @dev requests which are included in a single block.
     *
     * @param _userSeed VOR seed input provided by user
     * @param _requester Address of the requesting contract
     * @param _nonce User-specific nonce at the time of the request
     */
    function makeVORInputSeed(
        bytes32 _keyHash,
        uint256 _userSeed,
        address _requester,
        uint256 _nonce
    ) internal pure returns (uint256) {
        return uint256(keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)));
    }

    /**
     * @notice Returns the id for this request
     * @param _keyHash The serviceAgreement ID to be used for this request
     * @param _vORInputSeed The seed to be passed directly to the VOR
     * @return The id for this request
     *
     * @dev Note that _vORInputSeed is not the seed passed by the consuming
     * @dev contract, but the one generated by makeVORInputSeed
     */
    function makeRequestId(bytes32 _keyHash, uint256 _vORInputSeed) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(_keyHash, _vORInputSeed));
    }
}


/**
 * @title VORConsumerBase
 * @notice Interface for contracts using VOR randomness
 * @dev PURPOSE
 *
 * @dev Reggie the Random Oracle (not his real job) wants to provide randomness
 * to Vera the verifier in such a way that Vera can be sure he's not
 * making his output up to suit himself. Reggie provides Vera a public key
 * to which he knows the secret key. Each time Vera provides a seed to
 * Reggie, he gives back a value which is computed completely
 * deterministically from the seed and the secret key.
 *
 * @dev Reggie provides a proof by which Vera can verify that the output was
 * correctly computed once Reggie tells it to her, but without that proof,
 * the output is indistinguishable to her from a uniform random sample
 * from the output space.
 *
 * @dev The purpose of this contract is to make it easy for unrelated contracts
 * to talk to Vera the verifier about the work Reggie is doing, to provide
 * simple access to a verifiable source of randomness.
 *
 * @dev USAGE
 *
 * @dev Calling contracts must inherit from VORConsumerBase, and can
 * initialize VORConsumerBase's attributes in their constructor as
 * shown:
 *
 * ```
 *   contract VORConsumer {
 *     constuctor(<other arguments>, address _vorCoordinator, address _xfund)
 *       VORConsumerBase(_vorCoordinator, _xfund) public {
 *         <initialization with other arguments goes here>
 *       }
 *   }
 * ```
 * @dev The oracle will have given you an ID for the VOR keypair they have
 * committed to (let's call it keyHash), and have told you the minimum xFUND
 * price for VOR service. Make sure your contract has sufficient xFUND, and
 * call requestRandomness(keyHash, fee, seed), where seed is the input you
 * want to generate randomness from.
 *
 * @dev Once the VORCoordinator has received and validated the oracle's response
 * to your request, it will call your contract's fulfillRandomness method.
 *
 * @dev The randomness argument to fulfillRandomness is the actual random value
 * generated from your seed.
 *
 * @dev The requestId argument is generated from the keyHash and the seed by
 * makeRequestId(keyHash, seed). If your contract could have concurrent
 * requests open, you can use the requestId to track which seed is
 * associated with which randomness. See VORRequestIDBase.sol for more
 * details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind,
 * if your contract could have multiple requests in flight simultaneously.)
 *
 * @dev Colliding `requestId`s are cryptographically impossible as long as seeds
 * differ. (Which is critical to making unpredictable randomness! See the
 * next section.)
 *
 * @dev SECURITY CONSIDERATIONS
 *
 * @dev A method with the ability to call your fulfillRandomness method directly
 * could spoof a VOR response with any random value, so it's critical that
 * it cannot be directly called by anything other than this base contract
 * (specifically, by the VORConsumerBase.rawFulfillRandomness method).
 *
 * @dev For your users to trust that your contract's random behavior is free
 * from malicious interference, it's best if you can write it so that all
 * behaviors implied by a VOR response are executed *during* your
 * fulfillRandomness method. If your contract must store the response (or
 * anything derived from it) and use it later, you must ensure that any
 * user-significant behavior which depends on that stored value cannot be
 * manipulated by a subsequent VOR request.
 *
 * @dev Similarly, both miners and the VOR oracle itself have some influence
 * over the order in which VOR responses appear on the blockchain, so if
 * your contract could have multiple VOR requests in flight simultaneously,
 * you must ensure that the order in which the VOR responses arrive cannot
 * be used to manipulate your contract's user-significant behavior.
 *
 * @dev Since the ultimate input to the VOR is mixed with the block hash of the
 * block in which the request is made, user-provided seeds have no impact
 * on its economic security properties. They are only included for API
 * compatability with previous versions of this contract.
 *
 * @dev Since the block hash of the block which contains the requestRandomness
 * call is mixed into the input to the VOR *last*, a sufficiently powerful
 * miner could, in principle, fork the blockchain to evict the block
 * containing the request, forcing the request to be included in a
 * different block with a different hash, and therefore a different input
 * to the VOR. However, such an attack would incur a substantial economic
 * cost. This cost scales with the number of blocks the VOR oracle waits
 * until it calls responds to a request.
 */
abstract contract VORConsumerBase is VORRequestIDBase {
    using VORSafeMath for uint256;

    /**
     * @notice fulfillRandomness handles the VOR response. Your contract must
     * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
     * @notice principles to keep in mind when implementing your fulfillRandomness
     * @notice method.
     *
     * @dev VORConsumerBase expects its subcontracts to have a method with this
     * signature, and will call it once it has verified the proof
     * associated with the randomness. (It is triggered via a call to
     * rawFulfillRandomness, below.)
     *
     * @param requestId The Id initially returned by requestRandomness
     * @param randomness the VOR output
     */
    function fulfillRandomness(bytes32 requestId, uint256 randomness) internal virtual;

    /**
     * @notice requestRandomness initiates a request for VOR output given _seed
     *
     * @dev The fulfillRandomness method receives the output, once it's provided
     * by the Oracle, and verified by the vorCoordinator.
     *
     * @dev The _keyHash must already be registered with the VORCoordinator, and
     * the _fee must exceed the fee specified during registration of the
     * _keyHash.
     *
     * @dev The _seed parameter is vestigial, and is kept only for API
     * compatibility with older versions. It can't *hurt* to mix in some of
     * your own randomness, here, but it's not necessary because the VOR
     * oracle will mix the hash of the block containing your request into the
     * VOR seed it ultimately uses.
     *
     * @param _keyHash ID of public key against which randomness is generated
     * @param _fee The amount of xFUND to send with the request
     * @param _seed seed mixed into the input of the VOR.
     *
     * @return requestId unique ID for this request
     *
     * The returned requestId can be used to distinguish responses to
     * concurrent requests. It is passed as the first argument to
     * fulfillRandomness.
     */
    function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) internal returns (bytes32 requestId) {
        IVORCoordinator(vorCoordinator).randomnessRequest(_keyHash, _seed, _fee);
        // This is the seed passed to VORCoordinator. The oracle will mix this with
        // the hash of the block containing this request to obtain the seed/input
        // which is finally passed to the VOR cryptographic machinery.
        uint256 vORSeed = makeVORInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
        // nonces[_keyHash] must stay in sync with
        // VORCoordinator.nonces[_keyHash][this], which was incremented by the above
        // successful VORCoordinator.randomnessRequest.
        // This provides protection against the user repeating their input seed,
        // which would result in a predictable/duplicate output, if multiple such
        // requests appeared in the same block.
        nonces[_keyHash] = nonces[_keyHash].safeAdd(1);
        return makeRequestId(_keyHash, vORSeed);
    }

    /**
     * @notice _increaseVorCoordinatorAllowance is a helper function to increase token allowance for
     * the VORCoordinator
     * Allows this contract to increase the xFUND allowance for the VORCoordinator contract
     * enabling it to pay request fees on behalf of this contract.
     * NOTE: it is hightly recommended to wrap this around a function that uses,
     * for example, OpenZeppelin's onlyOwner modifier
     *
     * @param _amount uint256 amount to increase allowance by
     */
    function _increaseVorCoordinatorAllowance(uint256 _amount) internal returns (bool) {
        require(xFUND.increaseAllowance(vorCoordinator, _amount), "failed to increase allowance");
        return true;
    }

    /**
     * @notice _setVORCoordinator is a helper function to enable setting the VORCoordinator address
     * NOTE: it is hightly recommended to wrap this around a function that uses,
     * for example, OpenZeppelin's onlyOwner modifier
     *
     * @param _vorCoordinator address new VORCoordinator address
     */
    function _setVORCoordinator(address _vorCoordinator) internal {
        vorCoordinator = _vorCoordinator;
    }

    address internal immutable xFUNDAddress;
    IERC20_Ex internal immutable xFUND;
    address internal vorCoordinator;

    // Nonces for each VOR key from which randomness has been requested.
    //
    // Must stay in sync with VORCoordinator[_keyHash][this]
    /* keyHash */
    /* nonce */
    mapping(bytes32 => uint256) private nonces;

    /**
     * @param _vorCoordinator address of VORCoordinator contract
     * @param _xfund address of xFUND token contract
     */
    constructor(address _vorCoordinator, address _xfund) internal {
        vorCoordinator = _vorCoordinator;
        xFUNDAddress = _xfund;
        xFUND = IERC20_Ex(_xfund);
    }

    /**
     * @notice rawFulfillRandomness is called by VORCoordinator when it receives a valid VOR
     * proof. rawFulfillRandomness then calls fulfillRandomness, after validating
     * the origin of the call
     */
    function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external {
        require(msg.sender == vorCoordinator, "Only VORCoordinator can fulfill");
        fulfillRandomness(requestId, randomness);
    }
}


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


/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}


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


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}


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

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

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

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

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

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

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}


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

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

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

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

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


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


/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
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;

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

    /**
     * @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), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        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) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        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 overriden 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, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_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), "ERC721: transfer caller is not owner nor approved");

        _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), "ERC721: transfer caller is not owner nor approved");
        _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), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @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 _owners[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) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, 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),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @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), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

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

        _balances[to] += 1;
        _owners[tokenId] = to;

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

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

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

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

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

    /**
     * @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, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, 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("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * 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 {}
}


/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}


/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

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

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

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

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * 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` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * 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 override {
        super._beforeTokenTransfer(from, to, tokenId);

        if (from == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}


// @title Base64
// @notice Provides a function for encoding some bytes in base64
// @author Brecht Devos <[email protected]>
library Base64 {
    bytes internal constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /// @notice Encodes some bytes to the base64 representation
    function encode(bytes memory data) internal pure returns (string memory) {
        uint256 len = data.length;
        if (len == 0) return "";

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((len + 2) / 3);

        // Add some extra buffer at the end
        bytes memory result = new bytes(encodedLen + 32);

        bytes memory table = TABLE;

        assembly {
            let tablePtr := add(table, 1)
            let resultPtr := add(result, 32)

            for {
                let i := 0
            } lt(i, len) {

            } {
                i := add(i, 3)
                let input := and(mload(add(data, i)), 0xffffff)

                let out := mload(add(tablePtr, and(shr(18, input), 0x3F)))
                out := shl(8, out)
                out := add(out, and(mload(add(tablePtr, and(shr(12, input), 0x3F))), 0xFF))
                out := shl(8, out)
                out := add(out, and(mload(add(tablePtr, and(shr(6, input), 0x3F))), 0xFF))
                out := shl(8, out)
                out := add(out, and(mload(add(tablePtr, and(input, 0x3F))), 0xFF))
                out := shl(224, out)

                mstore(resultPtr, out)

                resultPtr := add(resultPtr, 4)
            }

            switch mod(len, 3)
            case 1 {
                mstore(sub(resultPtr, 2), shl(240, 0x3d3d))
            }
            case 2 {
                mstore(sub(resultPtr, 1), shl(248, 0x3d))
            }

            mstore(result, encodedLen)
        }

        return string(result);
    }
}


interface IPlayingCards {
    function getCardNumberAsUint(uint8 cardId) external view returns (uint8);
    function getCardSuitAsUint(uint8 cardId) external view returns (uint8);
    function getCardNumberAsStr(uint8 cardId) external view returns (string memory);
    function getCardSuitAsStr(uint8 cardId) external view returns (string memory);
    function getCardAsString(uint8 cardId) external view returns (string memory);
    function getCardAsSvg(uint8 cardId) external view returns (string memory);
    function getCardAsComponents(uint8 cardId) external view returns (uint8 number, uint8 suit);
    function getCardBody(uint8 numberId, uint8 suitId, uint256 fX, uint256 sX, uint256 rX) external pure returns (string memory);
    function getSuitPath(uint8 suitId) external pure returns (string memory);
    function getNumberPath(uint8 numberId) external pure returns (string memory);
}


contract HoldemHeroesBase is ERC721Enumerable, Ownable  {

    // a start-hand combination
    struct Hand {
        uint8 card1; // 0 - 51
        uint8 card2; // 0 - 51
    }

    uint256 public constant MAX_NFT_SUPPLY = 1326; // final totalSupply of NFTs

    // sha256 hash of all generated and shuffled hands
    bytes32 public constant HAND_PROVENANCE = 0xbcd1a23f7cca99ec419590e58d82db68573d59d2cdf88a901c5c25edea2c075d;

    // start index for mapping tokenId on to handId - set during the distribution phase
    uint256 public startingIndex;
    // time after which hands are randomised and allocated to token Ids
    uint256 public REVEAL_TIMESTAMP;

    // hands have been revealed
    bool public REVEALED;
    // ranks uploaded - used only during uploadHandRanks function
    bool public RANKS_UPLOADED;
    // the block number in which the final hands were revealed
    uint256 public revealBlock;

    // IPFS hash for provenance JSON - will be set when the last hand batch is revealed
    string public PROVENANCE_IPFS;

    // array of 1326 possible start hand combinations
    Hand[1326] public hands;

    // used during reveal function to ensure batches are uploaded sequentially
    // according to provenance
    uint16 public handUploadId;
    uint8 public nextExpectedBatchId = 0;
    // mapping to ensure batch is not re-uploaded. Only used during reveal function
    mapping(bytes32 => bool) private isHandRevealed;

    // Mapping to hold hand ranks. Requires populating during contract initialisation
    mapping (bytes32 => uint8) public handRanks;

    // The playing cards contract on which HEH is built
    IPlayingCards public immutable playingCards;

    /*
     * EVENTS
     */

    event BatchRevealed(uint16 startHandId, uint16 endHandId, bytes32 batchHash, uint8 batchId);
    event RanksInitialised();

    /**
     * @dev constructor
     * @dev initialises some basic variables.
     *
     * @param _revealTimestamp uint256 - unix timestamp for when cards will be revealed and distributed
     * @param _playingCards address - address of Playing Cards contract
     */
    constructor(uint256 _revealTimestamp, address _playingCards)
    ERC721("Holdem Heroes", "HEH")
    Ownable() {
        REVEAL_TIMESTAMP = _revealTimestamp;
        REVEALED = false;
        RANKS_UPLOADED = false;
        handUploadId = 0;
        playingCards = IPlayingCards(_playingCards);
    }

    /*
    * ADMIN FUNCTIONS
    */

    /**
     * @dev uploadHandRanks upload the 169 start hand ranks, which are referenced
     * @dev by the hand getter functions. Hand ranks are stored as a mapping of a
     * @dev sha256 hash and the integer rank value. The hash is generated from a
     * @dev concatenation of the word "rank" and the hand's name. e.g.
     * keccak256("rankA5s") => 28
     *
     * @param rankHashes bytes32[] array of sha256 hashes
     * @param ranks uint8[] array of corresponding ranks for rankHashes
     */
    function uploadHandRanks(bytes32[] memory rankHashes, uint8[] memory ranks) external onlyOwner {
        require(!RANKS_UPLOADED, "uploaded");
        for (uint8 i = 0; i < rankHashes.length; i++) {
            handRanks[rankHashes[i]] = ranks[i];
        }
        RANKS_UPLOADED = true;
        emit RanksInitialised();
    }

    /**
     * @dev withdrawETH allows contract owner to withdraw ether
     */
    function withdrawETH() external onlyOwner {
        payable(msg.sender).transfer(address(this).balance);
    }

    /**
     * @dev reveal is used to upload and reveal the generated start hand combinations.
     * @dev hands are uploaded in batches, with each batch containing n
     * @dev hands. each hand is a uint8[] array of card IDs, e.g. [2, 3]
     * @dev with each batch represented as a 2d array of hands, for example, [[2, 3], [3, 4], ...]
     * @dev Batches must be uploaded sequentially according to provenance.
     *
     * @param inputs uint8[2][] batch of hands
     * @param batchId uint8 id of the batch being revealed
     * @param ipfs string IPFS hash of provenance.json. Sent with final batch only
     */
    function reveal(uint8[2][] memory inputs, uint8 batchId, string memory ipfs) public onlyOwner {
        require(block.timestamp >= REVEAL_TIMESTAMP, "not yet");
        require(handUploadId < 1325, "revealed");
        require(batchId == nextExpectedBatchId, "seq incorrect");
        bytes32 dataHash = keccak256(abi.encodePacked(inputs));
        require(!isHandRevealed[dataHash], "already added");
        isHandRevealed[dataHash] = true;
        for (uint8 i = 0; i < inputs.length; i++) {
            hands[handUploadId] = Hand(inputs[i][0],inputs[i][1]);
            handUploadId = handUploadId + 1;
        }
        emit BatchRevealed(handUploadId - uint16(inputs.length), handUploadId - 1, dataHash, batchId);
        if (handUploadId == 1326) {
            REVEALED = true;
            PROVENANCE_IPFS = ipfs;
            revealBlock = block.number;
        } else {
            nextExpectedBatchId = nextExpectedBatchId + 1;
        }
    }

    /*
     * PUBLIC GETTERS
     */

    /**
     * @dev getHandShape returns the shape for a given hand ID, for example "Suited" or "s"
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @param abbreviate bool whether or not to abbreviate ("s" instead of Suited" if true)
     * @return string shape of hand
     */
    function getHandShape(uint16 handId, bool abbreviate) public validHandId(handId) view returns (string memory) {
        uint8 card1N = playingCards.getCardNumberAsUint(hands[handId].card1);
        uint8 card2N = playingCards.getCardNumberAsUint(hands[handId].card2);

        uint8 card1S = playingCards.getCardSuitAsUint(hands[handId].card1);
        uint8 card2S = playingCards.getCardSuitAsUint(hands[handId].card2);

        if (card1N == card2N) {
            return abbreviate ? "" : "Pair";
        } else if (card1S == card2S) {
            return abbreviate ? "s" : "Suited";
        } else {
            return abbreviate ? "o" : "Offsuit";
        }
    }

    /**
     * @dev getHandAsCardIds returns the card IDs (0 - 51) for a given hand ID, for example 12,24
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @return card1 uint8 ID of card 1 (0 - 51)
     * @return card2 uint8 ID of card 2 (0 - 51)
     */
    function getHandAsCardIds(uint16 handId) public validHandId(handId) view returns (uint8 card1, uint8 card2) {
        Hand storage hand = hands[handId];
        if (playingCards.getCardNumberAsUint(hand.card1) > playingCards.getCardNumberAsUint(hand.card2)) {
            return (hand.card1, hand.card2);
        } else {
            return (hand.card2, hand.card1);
        }
    }

    /**
     * @dev getHandName returns the canonical name for a given hand ID. This is a concatenation of
     * @dev Card1 + Card2 + Shape, with the cards ordered by card number in descending order.
     * @dev E.g. A5s
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @return string hand name
     */
    function getHandName(uint16 handId) public validHandId(handId) view returns (string memory) {
        string memory shape = getHandShape(handId, true);
        (uint8 card1, uint8 card2) = getHandAsCardIds(handId);

        return string(abi.encodePacked(playingCards.getCardNumberAsStr(card1), playingCards.getCardNumberAsStr(card2), shape));
    }

    /**
     * @dev getHandRank returns the canonical rank for a given hand ID. Lower is better
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @return string hand rank
     */
    function getHandRank(uint16 handId) public validHandId(handId) view returns (uint8) {
        return handRanks[keccak256(abi.encodePacked("rank", getHandName(handId)))];
    }

    /**
     * @dev getHandAsString returns a concatenation of the card names
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @return string hand - cards names concatenated, e.g. AsAc
     */
    function getHandAsString(uint16 handId) public validHandId(handId) view returns (string memory) {
        (uint8 card1, uint8 card2) = getHandAsCardIds(handId);
        return string(abi.encodePacked(playingCards.getCardAsString(card1), playingCards.getCardAsString(card2)));
    }

    /**
     * @dev getHandAsSvg returns the SVG XML for a hand, which can be rendered as an img src in a UI
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @return string SVG XML of a hand of 2 cards
     */
    function getHandAsSvg(uint16 handId) public validHandId(handId) view returns (string memory) {
        (uint8 card1, uint8 card2) = getHandAsCardIds(handId);

        string[4] memory parts;
        parts[0] = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 148 62\" width=\"5in\" height=\"2.147in\">";
        parts[1] = playingCards.getCardBody(playingCards.getCardNumberAsUint(card1), playingCards.getCardSuitAsUint(card1), 7, 32, 2);
        parts[2] = playingCards.getCardBody(playingCards.getCardNumberAsUint(card2), playingCards.getCardSuitAsUint(card2), 82, 107, 76);
        parts[3] = "</svg>";

        string memory output = string(
            abi.encodePacked(parts[0], parts[1], parts[2], parts[3])
        );
        return output;
    }

    /**
     * @dev getHandHash returns a hand's hash, which can be used to match against the
     * @dev published provenance. Hand hashes can be sequentially concatenated and the
     * @dev concatenation itself hashed (after removing each hand hash's 0x prefix)
     * @dev to get the provenance hash. This provenance hash should match both the published
     * @dev hash and the HAND_PROVENANCE constant in this contract
     *
     * @param handId uint16 ID of the hand from 0 - 1325
     * @return string hash of the hand
     */
    function getHandHash(uint16 handId) public validHandId(handId) view returns (bytes32) {
        (uint8 card1, uint8 card2) = getHandAsCardIds(handId);
        return keccak256(abi.encodePacked(
                toString(handId),
                getHandAsString(handId),
                toString(card1),
                toString(playingCards.getCardNumberAsUint(card1)),
                toString(playingCards.getCardSuitAsUint(card1)),
                toString(card2),
                toString(playingCards.getCardNumberAsUint(card2)),
                toString(playingCards.getCardSuitAsUint(card2))
            )
        );
    }

    /**
     * @dev tokenIdToHandId maps a given token ID onto its distributed hand ID
     * @dev Note - this will only run after all hands have been revealed
     * @dev and distributed.
     *
     * @param _tokenId uint256 ID of the NFT token from 0 - 1325
     * @return uint16 hand ID associate to the token
     */
    function tokenIdToHandId(uint256 _tokenId) public view returns (uint16) {
        require(_tokenId >= 0 && _tokenId < 1326, "invalid id");
        require(startingIndex > 0, "not distributed");
        return uint16((_tokenId + startingIndex) % MAX_NFT_SUPPLY);
    }

    /**
     * @dev tokenURI generates the base64 encoded JSON of the NFT itself. tokenURI will first call
     * @dev tokenIdToHandId to find which hand the token is for. It will then generate
     * @dev and output the encoded JSON containing the SVG image, name, description and
     * @dev attributes.
     * @dev Note - this will only run after all hands have been revealed
     * @dev and distributed.
     *
     * @param _tokenId uint256 ID of the NFT token from 0 - 1325
     * @return string the token's NFT JSON
     */
    function tokenURI(uint256 _tokenId) public view override returns (string memory) {
        // we need to map the token ID onto the assigned hand ID,
        // based on the distribution's startingIndex. This is only available
        // AFTER distribution has occurred, and will return an error otherwise
        uint16 handId = tokenIdToHandId(_tokenId);

        string memory handName = getHandAsString(handId);
        string memory shape = getHandShape(handId, false);
        string memory hand = getHandName(handId);
        string memory rank = toString(getHandRank(handId));

        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        "{\"name\": \"", handName,
                        "\", \"description\": \"holdemheroes.com\",",
                        getAttributes(shape, hand, rank),
                        "\"image\": \"data:image/svg+xml;base64,",
                        Base64.encode(bytes(getHandAsSvg(handId))),
                        "\"}"
                    )
                )
            )
        );
        string memory output = string(abi.encodePacked("data:application/json;base64,", json));

        return output;
    }

    /*
     * PRIVATE FUNCTIONS
     */

    /**
     * @dev getAttributes will generate the attributes JSON for embedding into the NFT JSON
     *
     * @param shape string shape
     * @param hand string hand
     * @param rank string rank
     * @return string attribute JSON
     */
    function getAttributes(string memory shape, string memory hand, string memory rank) private pure returns (string memory) {
        return string(
            abi.encodePacked(
                "\"attributes\": [{ \"trait_type\": \"Shape\", \"value\": \"", shape, "\"},",
                "{ \"trait_type\": \"Hand\", \"value\": \"", hand, "\"},",
                "{ \"trait_type\": \"Rank\", \"value\": \"", rank, "\"}],"
            )
        );
    }

    /**
     * @dev toString converts a given uint256 to a string. Primarily used in SVG, JSON, string name,
     * @dev and hash generation
     *
     * @param value uint256 number to convert
     * @return string number as a string
     */
    function toString(uint256 value) private pure returns (string memory) {
        // Inspired by OraclizeAPI"s implementation - MIT license
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
        uint256 _tmpN = value;
        if (_tmpN == 0) {
            return "0";
        }
        uint256 temp = _tmpN;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (_tmpN != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(_tmpN % 10)));
            _tmpN /= 10;
        }
        return string(buffer);
    }

    /*
     * MODIFIERS
     */

    /**
     * @dev validHandId ensures a given hand Id is valid
     *
     * @param handId uint16 id of hand
     */
    modifier validHandId(uint16 handId) {
        require(handId >= 0 && handId < 1326, "invalid handId");
        require(REVEALED, "not revealed");
        _;
    }
}


contract HoldemHeroes is Ownable, HoldemHeroesBase, VORConsumerBase  {
    using PRBMathSD59x18 for int256;

    // max number of NFTs allowed per address
    uint256 public MAX_PER_ADDRESS_OR_TX;
    // block number for when public sale opens
    uint256 public SALE_START_BLOCK_NUM;

    uint256 public basePostRevealPrice = 1 ether;

    /// ---------------------------
    /// ------- CRISP STATE -------
    /// ---------------------------

    ///@notice block on which last purchase occurred
    uint256 public lastPurchaseBlock;

    ///@notice block on which we start decaying price
    uint256 public priceDecayStartBlock;

    ///@notice Starting EMS, before time decay. 59.18-decimal fixed-point
    int256 public nextPurchaseStartingEMS;

    ///@notice Starting price for next purchase, before time decay. 59.18-decimal fixed-point
    int256 public nextPurchaseStartingPrice;

    /// ---------------------------
    /// ---- CRISP PARAMETERS -----
    /// ---------------------------

    ///@notice EMS target. 59.18-decimal fixed-point
    int256 public immutable targetEMS;

    ///@notice controls decay of sales in EMS. 59.18-decimal fixed-point
    int256 public immutable saleHalflife;

    ///@notice controls upward price movement. 59.18-decimal fixed-point
    int256 public immutable priceSpeed;

    ///@notice controls price decay. 59.18-decimal fixed-point
    int256 public immutable priceHalflife;

    /*
     * EVENTS
     */

    event DistributionBegun(bytes32 requestId, address sender);
    event DistributionResult(bytes32 requestId, uint256 randomness, uint256 startingIndex);

    /**
     * @dev constructor
     * @dev initialises some basic variables.
     * @dev CRISP implementation from https://github.com/FrankieIsLost/CRISP/blob/master/src/CRISP.sol
     *
     * @param _vorCoordinator address - address of VORCoordinator contract
     * @param _xfund address - address of xFUND contract
     * @param _playingCards address - address of Playing Cards contract
     * @param _saleStartBlockNum uint256 - block number for when pre-reveal sale starts. Allows time for card/rank init
     * @param _revealTimestamp uint256 - unix timestamp for when cards will be revealed and distributed
     * @param _maxNfts address - max number of NFTs a single wallet address can mint
     * @param _targetBlocksPerSale int256, e.g. 100
     * @param _saleHalflife int256, e.g. 700
     * @param _priceSpeed int256, e.g. 1
     * @param _priceSpeedDenominator int256, e.g. 4. If _priceSpeed param is 1, final priceSpeed will be 0.25
     * @param _priceHalflife int256, e.g. 100
     * @param _startingPrice int256, e.g. 100
     */
    constructor(
        address _vorCoordinator,
        address _xfund,
        address _playingCards,
        uint256 _saleStartBlockNum,
        uint256 _revealTimestamp,
        uint256 _maxNfts,
        int256 _targetBlocksPerSale,
        int256 _saleHalflife,
        int256 _priceSpeed,
        int256 _priceSpeedDenominator,
        int256 _priceHalflife,
        int256 _startingPrice
    )
    VORConsumerBase(_vorCoordinator, _xfund)
    HoldemHeroesBase(_revealTimestamp, _playingCards)
    {
        SALE_START_BLOCK_NUM = (_saleStartBlockNum > block.number) ? _saleStartBlockNum : block.number;

        MAX_PER_ADDRESS_OR_TX = _maxNfts;

        // CRISP
        lastPurchaseBlock = SALE_START_BLOCK_NUM;
        priceDecayStartBlock = SALE_START_BLOCK_NUM;

        // scale parameters - see https://github.com/FrankieIsLost/CRISP/blob/master/src/test/CRISP.t.sol
        int256 targetBlocksPerSale = PRBMathSD59x18.fromInt(
            _targetBlocksPerSale
        );

        saleHalflife = PRBMathSD59x18.fromInt(_saleHalflife);
        priceSpeed = PRBMathSD59x18.fromInt(_priceSpeed).div(PRBMathSD59x18.fromInt(_priceSpeedDenominator));
        priceHalflife = PRBMathSD59x18.fromInt(_priceHalflife);

        //calculate target EMS from target blocks per sale
        targetEMS = PRBMathSD59x18.fromInt(1).div(
            PRBMathSD59x18.fromInt(1) -
            PRBMathSD59x18.fromInt(2).pow(
                -targetBlocksPerSale.div(saleHalflife)
            )
        );

        nextPurchaseStartingEMS = targetEMS;

        nextPurchaseStartingPrice = PRBMathSD59x18.fromInt(int256(_startingPrice));
    }

    /*
     * ADMIN
     */

    /**
     * @dev setBasePostRevealPrice allows owner to adjust post-reveal price according to market
     *
     * @param newPrice uint256 new base price in wei
     */
    function setBasePostRevealPrice(uint256 newPrice) external onlyOwner {
        basePostRevealPrice = newPrice;
    }

    /*
     * CRISP FUNCTIONS
     */

    /**
     * @dev getCurrentEMS gets current EMS based on block number.
     * @dev implemented from https://github.com/FrankieIsLost/CRISP/blob/master/src/CRISP.sol
     *
     * @return result int256 59.18-decimal fixed-point
     */
    function getCurrentEMS() public view returns (int256 result) {
        int256 blockInterval = int256(block.number - lastPurchaseBlock);
        blockInterval = blockInterval.fromInt();
        int256 weightOnPrev = PRBMathSD59x18.fromInt(2).pow(
            -blockInterval.div(saleHalflife)
        );
        result = nextPurchaseStartingEMS.mul(weightOnPrev);
    }

    /**
     * @dev _getNftPrice get quote for purchasing in current block, decaying price as needed.
     * @dev implemented from https://github.com/FrankieIsLost/CRISP/blob/master/src/CRISP.sol
     *
     * @return result int256 59.18-decimal fixed-point
     */
    function _getNftPrice() internal view returns (int256 result) {
        if (block.number <= priceDecayStartBlock) {
            result = nextPurchaseStartingPrice;
        }
        //decay price if we are past decay start block
        else {
            int256 decayInterval = int256(block.number - priceDecayStartBlock)
            .fromInt();
            int256 decay = (-decayInterval).div(priceHalflife).exp();
            result = nextPurchaseStartingPrice.mul(decay);
        }
    }

    /**
     * @dev getNftPrice get quote for purchasing in current block, decaying price as needed
     * @dev implemented from https://github.com/FrankieIsLost/CRISP/blob/master/src/CRISP.sol
     *
     * @return result uint256 current price in wei
     */
    function getNftPrice() public view returns (uint256 result) {
        int256 pricePerNft = _getNftPrice();
        result = uint256(pricePerNft.toInt());
    }

    /**
     * @dev getPostRevealNftPrice get mint price for revealed tokens, based on the hand Rank
     * @dev lower rank = better hand = higher price. e.g. AA = rank 1 = high price
     * @dev Note - this can only be used in the event that there are unminted tokens
     * @dev once the pre-reveal sale has ended.
     *
     * @return result uint256 price in wei
     */
    function getPostRevealNftPrice(uint256 _tokenId) public view returns (uint256 result) {
        uint256 rank = uint256(getHandRank(tokenIdToHandId(_tokenId)));
        if(rank == 1) {
            result = basePostRevealPrice;
        } else {
            uint256 m = 100 - ((rank * 100) / 169); // get % as int
            m = (m < 10) ? 10 : m;
            result = (basePostRevealPrice * m) / 100;
        }
    }

    /**
     * @dev getNextStartingPriceGet starting price for next purchase before time decay
     * @dev implemented from https://github.com/FrankieIsLost/CRISP/blob/master/src/CRISP.sol
     *
     * @param lastPurchasePrice int256 last price as 59.18-decimal fixed-point
     * @return result int256 59.18-decimal fixed-point
     */
    function getNextStartingPrice(int256 lastPurchasePrice)
    public
    view
    returns (int256 result)
    {
        int256 mismatchRatio = nextPurchaseStartingEMS.div(targetEMS);
        if (mismatchRatio > PRBMathSD59x18.fromInt(1)) {
            result = lastPurchasePrice.mul(
                PRBMathSD59x18.fromInt(1) + mismatchRatio.mul(priceSpeed)
            );
        } else {
            result = lastPurchasePrice;
        }
    }

    /**
     * @dev getPriceDecayStartBlock Find block in which time based price decay should start
     * @dev implemented from https://github.com/FrankieIsLost/CRISP/blob/master/src/CRISP.sol
     *
     * @return result uint256 block number
     */
    function getPriceDecayStartBlock() internal view returns (uint256 result) {
        int256 mismatchRatio = nextPurchaseStartingEMS.div(targetEMS);
        //if mismatch ratio above 1, decay should start in future
        if (mismatchRatio > PRBMathSD59x18.fromInt(1)) {
            uint256 decayInterval = uint256(
                saleHalflife.mul(mismatchRatio.log2()).ceil().toInt()
            );
            result = block.number + decayInterval;
        }
        //else decay should start at the current block
        else {
            result = block.number;
        }
    }

    /*
     * MINT & DISTRIBUTION FUNCTIONS
     */

    /**
     * @dev mintNFTPreReveal is a public payable function which any user can call during the pre-reveal
     * @dev sale phase. This allows a user to mint up to MAX_PER_ADDRESS_OR_TX tokens. Tokens are
     * @dev minted sequentially. Mapping of token IDs on to hand IDs (according to provenance) is
     * @dev executed during the reveal & distribution phase, via a call to VOR.
     * @dev Correct ether value is expected to pay for tokens.
     *
     * @param _numberOfNfts uint256 number of NFTs to mint in this Tx
     */
    function mintNFTPreReveal(uint256 _numberOfNfts) external payable {
        uint256 numberOfNfts = (_numberOfNfts > 0) ? _numberOfNfts : 1;
        require(block.number >= SALE_START_BLOCK_NUM, "not started");
        require(totalSupply() < MAX_NFT_SUPPLY, "sold out");
        require(block.timestamp < REVEAL_TIMESTAMP, "ended");
        require(numberOfNfts <= MAX_PER_ADDRESS_OR_TX, "> max per tx");
        require(balanceOf(msg.sender) + numberOfNfts <= MAX_PER_ADDRESS_OR_TX, "> mint limit");
        require(totalSupply() + numberOfNfts <= MAX_NFT_SUPPLY, "exceeds supply");

        int256 pricePerNft = _getNftPrice();
        uint256 pricePerNftScaled = uint256(pricePerNft.toInt());
        uint256 totalCost = pricePerNftScaled * numberOfNfts;

        require(msg.value >= totalCost, "eth too low");

        for (uint256 i = 0; i < numberOfNfts; i++) {
            uint256 mintIndex = totalSupply();
            _safeMint(msg.sender, mintIndex);
        }

        //update CRISP state
        updateCrispState(pricePerNft, numberOfNfts);

    }

    /**
     * @dev mintNFTPostReveal is a public payable function which any user can call AFTER the pre-reveal
     * @dev sale phase. This allows a user to mint any available token ID that hasn't been sold yet.
     * @dev This function cannot be executed until hands have been revealed and distributed.
     * @dev Correct ether value is expected to pay for token.
     *
     * @param tokenId uint256 NFT Token ID to purchase
     */
    function mintNFTPostReveal(uint256 tokenId) external payable {
        uint256 price = getPostRevealNftPrice(tokenId);
        require(msg.value >= price, "eth too low");

        _safeMint(msg.sender, tokenId);
    }

    /**
     * @dev beginDistribution is called to initiate distribution and makes a VOR request to generate
     * @dev a random value. Can only be called after hands have been revealed according to provenance.
     *
     * @param _keyHash bytes32 key hash of the VOR Oracle that will handle the request
     * @param _fee uint256 xFUND fee to pay the VOR Oracle
     */
    function beginDistribution(bytes32 _keyHash, uint256 _fee) public onlyOwner canDistribute {
        _increaseVorCoordinatorAllowance(_fee);
        bytes32 requestId = requestRandomness(_keyHash, _fee, uint256(blockhash(block.number-10)));
        emit DistributionBegun(requestId, msg.sender);
    }

    /**
     * @dev fallbackDistribution is an emergency fallback function which can be called in the event
     * @dev of the fulfillRandomness function failing. It can only be called by the contract owner
     * @dev and should only be called if beginDistribution failed.
     */
    function fallbackDistribution() public onlyOwner canDistribute {
        uint256 sourceBlock = revealBlock;

        // Just a sanity check (EVM only stores last 256 block hashes)
        if (block.number - revealBlock > 255) {
            sourceBlock = block.number-1;
        }

        uint256 randomness = uint(blockhash(sourceBlock));

        checkAndSetStartIdx(randomness);

        emit DistributionResult(0x0, 0, startingIndex);
    }

    /**
     * @dev checkAndSetStartIdx is an internal function which will take the generated randomness
     * @dev and calculate/set the startingIndex mapping value.
     *
     * @param _randomness uint256 generated randomness value from VOR etc.
     */
    function checkAndSetStartIdx(uint256 _randomness) internal {
        // calculate based on randomness
        startingIndex = _randomness % (MAX_NFT_SUPPLY-1);
        // Prevent default sequence
        if (startingIndex == 0) {
            startingIndex = 1;
        }
        if (startingIndex > 1325) {
            startingIndex = 1325;
        }
    }

    /**
     * @dev fulfillRandomness is called by the VOR Oracle to fulfil the randomness request.
     * @dev The randomness value sent is used to calculate the start array Idx onto which
     * @dev hand IDs are mapped on to the NFT Token IDs.
     * @dev Can only be called by the correct VOR Oracle, and only via the VORCoordinator contract.
     *
     * @param _requestId bytes32 ID of the request fulfilled by the Oracle
     * @param _randomness uint256 the random number generated by the VOR Oracle
     */
    function fulfillRandomness(bytes32 _requestId, uint256 _randomness) internal override {
        require(startingIndex == 0, "already done");
        checkAndSetStartIdx(_randomness);
        emit DistributionResult(_requestId, _randomness, startingIndex);
    }

    /**
     * @dev updateCrispState updates the CRISP parameters for dynamic pricing
     *
     * @param price int256 current price per NFT paid by user
     * @param numMinted uint256 number minted in this Tx
     */
    function updateCrispState(int256 price, uint256 numMinted) internal {
        nextPurchaseStartingEMS = getCurrentEMS() + PRBMathSD59x18.fromInt(int256(numMinted));
        nextPurchaseStartingPrice = getNextStartingPrice(price);
        priceDecayStartBlock = getPriceDecayStartBlock();
        lastPurchaseBlock = block.number;
    }

    /*
     * MODIFIERS
     */

    /**
     * @dev canDistribute checks it's time to distribute
     */
    modifier canDistribute() {
        require(startingIndex == 0, "already done");
        require(REVEALED, "not revealed");
        _;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_vorCoordinator","type":"address"},{"internalType":"address","name":"_xfund","type":"address"},{"internalType":"address","name":"_playingCards","type":"address"},{"internalType":"uint256","name":"_saleStartBlockNum","type":"uint256"},{"internalType":"uint256","name":"_revealTimestamp","type":"uint256"},{"internalType":"uint256","name":"_maxNfts","type":"uint256"},{"internalType":"int256","name":"_targetBlocksPerSale","type":"int256"},{"internalType":"int256","name":"_saleHalflife","type":"int256"},{"internalType":"int256","name":"_priceSpeed","type":"int256"},{"internalType":"int256","name":"_priceSpeedDenominator","type":"int256"},{"internalType":"int256","name":"_priceHalflife","type":"int256"},{"internalType":"int256","name":"_startingPrice","type":"int256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__CeilOverflow","type":"error"},{"inputs":[],"name":"PRBMathSD59x18__DivInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"rAbs","type":"uint256"}],"name":"PRBMathSD59x18__DivOverflow","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__Exp2InputTooBig","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__ExpInputTooBig","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__FromIntOverflow","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__FromIntUnderflow","type":"error"},{"inputs":[{"internalType":"int256","name":"x","type":"int256"}],"name":"PRBMathSD59x18__LogInputTooSmall","type":"error"},{"inputs":[],"name":"PRBMathSD59x18__MulInputTooSmall","type":"error"},{"inputs":[{"internalType":"uint256","name":"rAbs","type":"uint256"}],"name":"PRBMathSD59x18__MulOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"}],"name":"PRBMath__MulDivFixedPointOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"startHandId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"endHandId","type":"uint16"},{"indexed":false,"internalType":"bytes32","name":"batchHash","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"batchId","type":"uint8"}],"name":"BatchRevealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"DistributionBegun","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"randomness","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingIndex","type":"uint256"}],"name":"DistributionResult","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":[],"name":"RanksInitialised","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":"HAND_PROVENANCE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_NFT_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PER_ADDRESS_OR_TX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVENANCE_IPFS","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RANKS_UPLOADED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVEALED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVEAL_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SALE_START_BLOCK_NUM","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":[],"name":"basePostRevealPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_keyHash","type":"bytes32"},{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"beginDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fallbackDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEMS","outputs":[{"internalType":"int256","name":"result","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"}],"name":"getHandAsCardIds","outputs":[{"internalType":"uint8","name":"card1","type":"uint8"},{"internalType":"uint8","name":"card2","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"}],"name":"getHandAsString","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"}],"name":"getHandAsSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"}],"name":"getHandHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"}],"name":"getHandName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"}],"name":"getHandRank","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"handId","type":"uint16"},{"internalType":"bool","name":"abbreviate","type":"bool"}],"name":"getHandShape","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"lastPurchasePrice","type":"int256"}],"name":"getNextStartingPrice","outputs":[{"internalType":"int256","name":"result","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNftPrice","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getPostRevealNftPrice","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"handRanks","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"handUploadId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hands","outputs":[{"internalType":"uint8","name":"card1","type":"uint8"},{"internalType":"uint8","name":"card2","type":"uint8"}],"stateMutability":"view","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":[],"name":"lastPurchaseBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mintNFTPostReveal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numberOfNfts","type":"uint256"}],"name":"mintNFTPreReveal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextExpectedBatchId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPurchaseStartingEMS","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPurchaseStartingPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"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":"playingCards","outputs":[{"internalType":"contract IPlayingCards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceDecayStartBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceHalflife","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceSpeed","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint256","name":"randomness","type":"uint256"}],"name":"rawFulfillRandomness","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[2][]","name":"inputs","type":"uint8[2][]"},{"internalType":"uint8","name":"batchId","type":"uint8"},{"internalType":"string","name":"ipfs","type":"string"}],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revealBlock","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":"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":[],"name":"saleHalflife","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"setBasePostRevealPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startingIndex","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":"targetEMS","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenIdToHandId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","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":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"rankHashes","type":"bytes32[]"},{"internalType":"uint8[]","name":"ranks","type":"uint8[]"}],"name":"uploadHandRanks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]

61016060405261053e805462ff000019169055670de0b6b3a7640000610545553480156200002c57600080fd5b50604051620073f1380380620073f18339810160408190526200004f9162001217565b8b8b898c6040518060400160405280600d81526020016c486f6c64656d204865726f657360981b815250604051806040016040528060038152602001620908a960eb1b8152508160009080519060200190620000ad92919062001159565b508051620000c390600190602084019062001159565b505050620000e0620000da620002c560201b60201c565b620002c9565b600c91909155600d805461ffff1990811690915561053e805490911690556001600160a01b0390811660805261054180546001600160a01b031916938216939093179092551660a081905260c0524389116200013d57436200013f565b885b6105448190556105438890556105468190556105475560006200016e876200031b602090811b620030e817901c565b905062000186866200031b60201b620030e81760201c565b6101008181525050620001d2620001a8856200031b60201b620030e81760201c565b620001be876200031b60201b620030e81760201c565b620003ae60201b620031731790919060201c565b6101208181525050620001f0836200031b60201b620030e81760201c565b61014081815250506200028d620002536200021d6101005184620003ae60201b620031731790919060201c565b6200022890620012d1565b6200023f60026200031b60201b620030e81760201c565b6200049960201b620032451790919060201c565b6200026a60016200031b60201b620030e81760201c565b620002769190620012f0565b620001be60016200031b60201b620030e81760201c565b60e081905261054855620002ad826200031b602090811b620030e817901c565b6105495550620013a29b505050505050505050505050565b3390565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60007809392ee8e921d5d073aff322e62439fcf32d7f344649470f8f19821215620003615760405163e608e18b60e01b8152600481018390526024015b60405180910390fd5b7809392ee8e921d5d073aff322e62439fcf32d7f344649470f90821315620003a0576040516371f72a3160e01b81526004810183905260240162000358565b50670de0b6b3a76400000290565b6000600160ff1b831480620003c65750600160ff1b82145b15620003e55760405163b3c754a360e01b815260040160405180910390fd5b60008060008512620003f85784620003fd565b846000035b9150600084126200040f578362000414565b836000035b905060006200043883670de0b6b3a764000084620004ee60201b6200328e1760201c565b90506001600160ff1b038111156200046757604051637cb4bef560e01b81526004810182905260240162000358565b6000198087139086138082186001146200048257826200048d565b6200048d83620012d1565b98975050505050505050565b600082600003620004c5578115620004b3576000620004bd565b670de0b6b3a76400005b9050620004e8565b620004e5620004df620004d885620005c8565b84620006c2565b6200079b565b90505b92915050565b60008080600019858709858702925082811083820303915050806000036200052d5783828162000522576200052262001335565b0492505050620005c1565b8381106200055957604051631dcf306360e21b8152600481018290526024810185905260440162000358565b600084868809851960019081018716968790049682860381900495909211909303600082900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b6000808213620005ef5760405163309fa7dd60e11b81526004810183905260240162000358565b6000670de0b6b3a764000083126200060a5750600162000624565b6000199050826ec097ce7bc90715b34b9f10000000000492505b600062000646670de0b6b3a764000085056200085760201b6200335a1760201c565b670de0b6b3a764000081029350905083811d670de0b6b3a763ffff1981016200067157505002919050565b6706f05b59d3b200005b6000811315620006b957670de0b6b3a7640000828002059150671bc16d674ec800008212620006b0579384019360019190911d905b60011d6200067b565b50505002919050565b6000600160ff1b831480620006da5750600160ff1b82145b15620006f957604051630d01a11b60e21b815260040160405180910390fd5b600080600085126200070c578462000711565b846000035b91506000841262000723578362000728565b836000035b905060006200074383836200095360201b620034431760201c565b90506001600160ff1b03811115620007725760405163bf79e8d960e01b81526004810182905260240162000358565b6000198087139086138082186001146200078d57826200048d565b505060000395945050505050565b600080821215620007f75768033dd1780914b9711419821215620007c157506000919050565b620007d060008390036200079b565b6ec097ce7bc90715b34b9f100000000081620007f057620007f062001335565b0592915050565b680a688906bd8b0000008212620008255760405163e69458f960e01b81526004810183905260240162000358565b6000670de0b6b3a7640000604084901b0490506200084e8162000a1d60201b620035091760201c565b9150505b919050565b6000600160801b82106200087a57608091821c916200087790826200134b565b90505b680100000000000000008210620008a057604091821c916200089d90826200134b565b90505b6401000000008210620008c257602091821c91620008bf90826200134b565b90505b620100008210620008e257601091821c91620008df90826200134b565b90505b61010082106200090157600891821c91620008fe90826200134b565b90505b601082106200091f57600491821c916200091c90826200134b565b90505b600482106200093d57600291821c916200093a90826200134b565b90505b600282106200085257620004e86001826200134b565b60008080600019848609848602925082811083820303915050670de0b6b3a76400008110620009995760405163698d9a0160e11b81526004810182905260240162000358565b600080670de0b6b3a764000086880991506706f05b59d3b1ffff8211905082600003620009d95780670de0b6b3a7640000850401945050505050620004e8565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b600160bf1b67800000000000000082161562000a425768016a09e667f3bcc9090260401c5b67400000000000000082161562000a62576801306fe0a31b7152df0260401c5b67200000000000000082161562000a82576801172b83c7d517adce0260401c5b67100000000000000082161562000aa25768010b5586cf9890f62a0260401c5b67080000000000000082161562000ac2576801059b0d31585743ae0260401c5b67040000000000000082161562000ae257680102c9a3e778060ee70260401c5b67020000000000000082161562000b025768010163da9fb33356d80260401c5b67010000000000000082161562000b2257680100b1afa5abcbed610260401c5b668000000000000082161562000b415768010058c86da1c09ea20260401c5b664000000000000082161562000b60576801002c605e2e8cec500260401c5b662000000000000082161562000b7f57680100162f3904051fa10260401c5b661000000000000082161562000b9e576801000b175effdc76ba0260401c5b660800000000000082161562000bbd57680100058ba01fb9f96d0260401c5b660400000000000082161562000bdc5768010002c5cc37da94920260401c5b660200000000000082161562000bfb576801000162e525ee05470260401c5b660100000000000082161562000c1a5768010000b17255775c040260401c5b6580000000000082161562000c38576801000058b91b5bc9ae0260401c5b6540000000000082161562000c5657680100002c5c89d5ec6d0260401c5b6520000000000082161562000c745768010000162e43f4f8310260401c5b6510000000000082161562000c9257680100000b1721bcfc9a0260401c5b6508000000000082161562000cb05768010000058b90cf1e6e0260401c5b6504000000000082161562000cce576801000002c5c863b73f0260401c5b6502000000000082161562000cec57680100000162e430e5a20260401c5b6501000000000082161562000d0a576801000000b1721835510260401c5b64800000000082161562000d2757680100000058b90c0b490260401c5b64400000000082161562000d445768010000002c5c8601cc0260401c5b64200000000082161562000d61576801000000162e42fff00260401c5b64100000000082161562000d7e5768010000000b17217fbb0260401c5b64080000000082161562000d9b576801000000058b90bfce0260401c5b64040000000082161562000db857680100000002c5c85fe30260401c5b64020000000082161562000dd55768010000000162e42ff10260401c5b64010000000082161562000df257680100000000b17217f80260401c5b638000000082161562000e0e5768010000000058b90bfc0260401c5b634000000082161562000e2a576801000000002c5c85fe0260401c5b632000000082161562000e4657680100000000162e42ff0260401c5b631000000082161562000e62576801000000000b17217f0260401c5b630800000082161562000e7e57680100000000058b90c00260401c5b630400000082161562000e9a5768010000000002c5c8600260401c5b630200000082161562000eb6576801000000000162e4300260401c5b630100000082161562000ed25768010000000000b172180260401c5b6280000082161562000eed576801000000000058b90c0260401c5b6240000082161562000f0857680100000000002c5c860260401c5b6220000082161562000f235768010000000000162e430260401c5b6210000082161562000f3e57680100000000000b17210260401c5b6208000082161562000f595768010000000000058b910260401c5b6204000082161562000f74576801000000000002c5c80260401c5b6202000082161562000f8f57680100000000000162e40260401c5b6201000082161562000faa576801000000000000b1720260401c5b61800082161562000fc457680100000000000058b90260401c5b61400082161562000fde5768010000000000002c5d0260401c5b61200082161562000ff8576801000000000000162e0260401c5b611000821615620010125768010000000000000b170260401c5b6108008216156200102c576801000000000000058c0260401c5b6104008216156200104657680100000000000002c60260401c5b6102008216156200106057680100000000000001630260401c5b6101008216156200107a57680100000000000000b10260401c5b60808216156200109357680100000000000000590260401c5b6040821615620010ac576801000000000000002c0260401c5b6020821615620010c557680100000000000000160260401c5b6010821615620010de576801000000000000000b0260401c5b6008821615620010f757680100000000000000060260401c5b60048216156200111057680100000000000000030260401c5b60028216156200112957680100000000000000010260401c5b60018216156200114257680100000000000000010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b828054620011679062001366565b90600052602060002090601f0160209004810192826200118b5760008555620011d6565b82601f10620011a657805160ff1916838001178555620011d6565b82800160010185558215620011d6579182015b82811115620011d6578251825591602001919060010190620011b9565b50620011e4929150620011e8565b5090565b5b80821115620011e45760008155600101620011e9565b80516001600160a01b03811681146200085257600080fd5b6000806000806000806000806000806000806101808d8f0312156200123b57600080fd5b620012468d620011ff565b9b506200125660208e01620011ff565b9a506200126660408e01620011ff565b995060608d0151985060808d0151975060a08d0151965060c08d0151955060e08d015194506101008d015193506101208d015192506101408d015191506101608d015190509295989b509295989b509295989b565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b8201620012e957620012e9620012bb565b5060000390565b60008083128015600160ff1b850184121615620013115762001311620012bb565b6001600160ff1b03840183138116156200132f576200132f620012bb565b50500390565b634e487b7160e01b600052601260045260246000fd5b60008219821115620013615762001361620012bb565b500190565b600181811c908216806200137b57607f821691505b6020821081036200139c57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e051610100516101205161014051615f4f620014a260003960008181610af301526142410152600081816109c501526118160152600081816108a001528181610c680152614a0501526000818161069c015281816117c901526149ab015260006144fd0152600050506000818161073401528181610f9b0152818161102601528181611140015281816111cb01528181611bba01528181611c5201528181611cb101528181611d040152818161226e015281816122fd0152818161258a015281816126190152818161290d0152818161299e01528181612b2c01528181612bdb01528181612c8e0152612d3d0152615f4f6000f3fe6080604052600436106103c35760003560e01c80638e6afff9116101f2578063c97513431161010d578063df1cb687116100a0578063f2fde38b1161006f578063f2fde38b14610b93578063f3231e4314610bb3578063f67a35df14610bd3578063fc19521e14610bf357600080fd5b8063df1cb68714610ae1578063e086e5ec14610b15578063e985e9c514610b2a578063efa6dba214610b7357600080fd5b8063d480c928116100dc578063d480c92814610a89578063d8328d3214610a9e578063da41672f14610ab5578063defadae114610acc57600080fd5b8063c975134314610a1c578063cb774d4714610a3c578063cb96e2b014610a52578063cee2b67714610a6957600080fd5b8063a76a958711610185578063c2a99f5d11610154578063c2a99f5d14610993578063c4108ccd146109b3578063c4912774146109e7578063c87b56dd146109fc57600080fd5b8063a76a958714610930578063b5077f441461094a578063b846a2b414610960578063b88d4fde1461097357600080fd5b8063a17716ac116101c1578063a17716ac146108c2578063a22cb465146108d9578063a27e5487146108f9578063a6f593751461091057600080fd5b80638e6afff91461081f57806394985ddd1461085957806395d89b411461087957806396d4fc201461088e57600080fd5b806346551621116102e25780636233e31811610275578063715018a611610244578063715018a6146107ac57806372fca5d0146107c157806386f84119146107e15780638da5cb5b1461080157600080fd5b80636233e318146107225780636352211e1461075657806366bb81c71461077657806370a082311461078c57600080fd5b80634eebd25f116102b15780634eebd25f1461068a5780634f6ccce7146106be578063544df5b1146106de57806356f02b261461070f57600080fd5b806346551621146105f0578063468fe8481461061f57806346a763701461063f57806349a0088f1461065657600080fd5b806314665ce81161035a5780632f745c59116103295780632f745c591461055d5780632ff46f9d1461057d57806332868c2f146105b057806342842e0e146105d057600080fd5b806314665ce8146104f257806318160ddd1461051257806318e20a381461052757806323b872dd1461053d57600080fd5b8063081812fc11610396578063081812fc14610459578063095ea7b3146104915780630d18b702146104b35780630fbec443146104d357600080fd5b806301ffc9a7146103c857806305c8c51f146103fd57806306e32b641461042257806306fdde0314610437575b600080fd5b3480156103d457600080fd5b506103e86103e3366004614fca565b610c13565b60405190151581526020015b60405180910390f35b34801561040957600080fd5b506104146105465481565b6040519081526020016103f4565b34801561042e57600080fd5b50610414610c3e565b34801561044357600080fd5b5061044c610cbd565b6040516103f4919061503f565b34801561046557600080fd5b50610479610474366004615052565b610d4f565b6040516001600160a01b0390911681526020016103f4565b34801561049d57600080fd5b506104b16104ac366004615082565b610de9565b005b3480156104bf57600080fd5b5061044c6104ce3660046150be565b610efe565b3480156104df57600080fd5b50600d546103e890610100900460ff1681565b3480156104fe57600080fd5b506104b161050d366004615052565b611327565b34801561051e57600080fd5b50600854610414565b34801561053357600080fd5b50610414600c5481565b34801561054957600080fd5b506104b16105583660046150d9565b611357565b34801561056957600080fd5b50610414610578366004615082565b611388565b34801561058957600080fd5b5061053e5461059e9062010000900460ff1681565b60405160ff90911681526020016103f4565b3480156105bc57600080fd5b506104b16105cb366004615249565b61141e565b3480156105dc57600080fd5b506104b16105eb3660046150d9565b6117a6565b3480156105fc57600080fd5b5061053e5461060c9061ffff1681565b60405161ffff90911681526020016103f4565b34801561062b57600080fd5b5061041461063a366004615052565b6117c1565b34801561064b57600080fd5b506104146105495481565b34801561066257600080fd5b506104147fbcd1a23f7cca99ec419590e58d82db68573d59d2cdf88a901c5c25edea2c075d81565b34801561069657600080fd5b506104147f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ca57600080fd5b506104146106d9366004615052565b611863565b3480156106ea57600080fd5b5061059e6106f9366004615052565b6105406020526000908152604090205460ff1681565b6104b161071d366004615052565b6118f6565b34801561072e57600080fd5b506104797f000000000000000000000000000000000000000000000000000000000000000081565b34801561076257600080fd5b50610479610771366004615052565b61194f565b34801561078257600080fd5b50610414600e5481565b34801561079857600080fd5b506104146107a7366004615367565b6119c6565b3480156107b857600080fd5b506104b1611a4d565b3480156107cd57600080fd5b5061060c6107dc366004615052565b611a83565b3480156107ed57600080fd5b506104146107fc3660046150be565b611b22565b34801561080d57600080fd5b50600a546001600160a01b0316610479565b34801561082b57600080fd5b5061083f61083a366004615052565b611d72565b6040805160ff9384168152929091166020830152016103f4565b34801561086557600080fd5b506104b1610874366004615382565b611d96565b34801561088557600080fd5b5061044c611dfb565b34801561089a57600080fd5b506104147f000000000000000000000000000000000000000000000000000000000000000081565b3480156108ce57600080fd5b506104146105485481565b3480156108e557600080fd5b506104b16108f43660046153b2565b611e0a565b34801561090557600080fd5b506104146105435481565b34801561091c57600080fd5b5061041461092b366004615052565b611ece565b34801561093c57600080fd5b50600d546103e89060ff1681565b34801561095657600080fd5b5061041461052e81565b6104b161096e366004615052565b611f51565b34801561097f57600080fd5b506104b161098e3660046153e9565b6121ba565b34801561099f57600080fd5b5061044c6109ae3660046150be565b6121ec565b3480156109bf57600080fd5b506104147f000000000000000000000000000000000000000000000000000000000000000081565b3480156109f357600080fd5b506104146123a1565b348015610a0857600080fd5b5061044c610a17366004615052565b6123bd565b348015610a2857600080fd5b5061059e610a373660046150be565b61247f565b348015610a4857600080fd5b50610414600b5481565b348015610a5e57600080fd5b506104146105455481565b348015610a7557600080fd5b5061044c610a843660046150be565b612517565b348015610a9557600080fd5b506104b16126ba565b348015610aaa57600080fd5b506104146105445481565b348015610ac157600080fd5b506104146105475481565b348015610ad857600080fd5b5061044c61279e565b348015610aed57600080fd5b506104147f000000000000000000000000000000000000000000000000000000000000000081565b348015610b2157600080fd5b506104b161282c565b348015610b3657600080fd5b506103e8610b45366004615465565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b348015610b7f57600080fd5b5061083f610b8e3660046150be565b612885565b348015610b9f57600080fd5b506104b1610bae366004615367565b612a46565b348015610bbf57600080fd5b5061044c610bce366004615498565b612ade565b348015610bdf57600080fd5b506104b1610bee366004615523565b612ee9565b348015610bff57600080fd5b506104b1610c0e366004615382565b61301a565b60006001600160e01b0319821663780e9d6360e01b1480610c385750610c3882613c05565b92915050565b6000806105465443610c5091906155f2565b9050610c5b816130e8565b90506000610ca5610c8c837f0000000000000000000000000000000000000000000000000000000000000000613173565b610c9590615609565b610c9f60026130e8565b90613245565b61054854909150610cb69082613c55565b9250505090565b606060008054610ccc90615625565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf890615625565b8015610d455780601f10610d1a57610100808354040283529160200191610d45565b820191906000526020600020905b815481529060010190602001808311610d2857829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b0316610dcd5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000610df48261194f565b9050806001600160a01b0316836001600160a01b031603610e615760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610dc4565b336001600160a01b0382161480610e7d5750610e7d8133610b45565b610eef5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610dc4565b610ef98383613d17565b505050565b60608161052e8161ffff1610610f265760405162461bcd60e51b8152600401610dc490615659565b600d5460ff16610f485760405162461bcd60e51b8152600401610dc490615681565b600080610f5485612885565b91509150610f60614efd565b6040518060c0016040528060858152602001615e55608591398152604051635693cc8d60e01b815260ff841660048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906346a0b33e908290635693cc8d90602401602060405180830381865afa158015610fea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100e91906156bd565b604051631cb0f60760e01b815260ff871660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631cb0f60790602401602060405180830381865afa158015611075573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109991906156bd565b6040516001600160e01b031960e085901b16815260ff92831660048201529116602482015260076044820152602060648201526002608482015260a401600060405180830381865afa1580156110f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261111b91908101906156da565b6020820152604051635693cc8d60e01b815260ff831660048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906346a0b33e908290635693cc8d90602401602060405180830381865afa15801561118f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b391906156bd565b604051631cb0f60760e01b815260ff861660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631cb0f60790602401602060405180830381865afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e91906156bd565b6040516001600160e01b031960e085901b16815260ff92831660048201529116602482015260526044820152606b6064820152604c608482015260a401600060405180830381865afa158015611298573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c091908101906156da565b60408281019182528051808201825260068152651e17b9bb339f60d11b602080830191909152606085018290528451818601519451935160009561130a9592949093909101615748565b60408051601f198184030181529190529550505050505b50919050565b600a546001600160a01b031633146113515760405162461bcd60e51b8152600401610dc49061579f565b61054555565b6113613382613d85565b61137d5760405162461bcd60e51b8152600401610dc4906157d4565b610ef9838383613e78565b6000611393836119c6565b82106113f55760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610dc4565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600a546001600160a01b031633146114485760405162461bcd60e51b8152600401610dc49061579f565b600c544210156114845760405162461bcd60e51b81526020600482015260076024820152661b9bdd081e595d60ca1b6044820152606401610dc4565b61053e5461052d61ffff909116106114c95760405162461bcd60e51b81526020600482015260086024820152671c995d99585b195960c21b6044820152606401610dc4565b61053e5460ff8381166201000090920416146115175760405162461bcd60e51b815260206004820152600d60248201526c1cd95c481a5b98dbdc9c9958dd609a1b6044820152606401610dc4565b60008360405160200161152a9190615825565b60408051601f198184030181529181528151602092830120600081815261053f90935291205490915060ff16156115935760405162461bcd60e51b815260206004820152600d60248201526c185b1c9958591e481859191959609a1b6044820152606401610dc4565b600081815261053f60205260408120805460ff191660011790555b84518160ff1610156116ba576040518060400160405280868360ff16815181106115da576115da6156a7565b60200260200101516000600281106115f4576115f46156a7565b602002015160ff168152602001868360ff1681518110611616576116166156a7565b6020026020010151600160028110611630576116306156a7565b602002015160ff16905261053e5460109061ffff1661052e8110611656576116566156a7565b82519101805460209093015160ff9081166101000261ffff1990941692169190911791909117905561053e546116919061ffff166001615884565b61053e805461ffff191661ffff92909216919091179055806116b2816158aa565b9150506115ae565b50835161053e547f28164971f0369b47dcecec8a5f7579a452938bd58e9c2e78dd7d4404aba9308c916116f09161ffff166158c9565b61053e546117049060019061ffff166158c9565b6040805161ffff9384168152929091166020830152810183905260ff8516606082015260800160405180910390a161053e5461ffff1661052e0361176c57600d805460ff19166001179055815161176290600f906020850190614f24565b5043600e556117a0565b61053e546117849062010000900460ff1660016158ec565b61053e60026101000a81548160ff021916908360ff1602179055505b50505050565b610ef9838383604051806020016040528060008152506121ba565b6000806117fa7f00000000000000000000000000000000000000000000000000000000000000006105485461317390919063ffffffff16565b905061180660016130e8565b81131561185c5761185561183a827f0000000000000000000000000000000000000000000000000000000000000000613c55565b61184460016130e8565b61184e9190615911565b8490613c55565b9150611321565b5090919050565b600061186e60085490565b82106118d15760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610dc4565b600882815481106118e4576118e46156a7565b90600052602060002001549050919050565b600061190182611ece565b9050803410156119415760405162461bcd60e51b815260206004820152600b60248201526a65746820746f6f206c6f7760a81b6044820152606401610dc4565b61194b3383614023565b5050565b6000818152600260205260408120546001600160a01b031680610c385760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610dc4565b60006001600160a01b038216611a315760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610dc4565b506001600160a01b031660009081526003602052604090205490565b600a546001600160a01b03163314611a775760405162461bcd60e51b8152600401610dc49061579f565b611a81600061403d565b565b600061052e8210611ac35760405162461bcd60e51b815260206004820152600a6024820152691a5b9d985b1a59081a5960b21b6044820152606401610dc4565b6000600b5411611b075760405162461bcd60e51b815260206004820152600f60248201526e1b9bdd08191a5cdd1c9a589d5d1959608a1b6044820152606401610dc4565b61052e600b5483611b189190615952565b610c389190615980565b60008161052e8161ffff1610611b4a5760405162461bcd60e51b8152600401610dc490615659565b600d5460ff16611b6c5760405162461bcd60e51b8152600401610dc490615681565b600080611b7885612885565b91509150611b898561ffff1661408f565b611b9286612517565b611b9e8460ff1661408f565b604051635693cc8d60e01b815260ff86166004820152611c36907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635693cc8d906024015b602060405180830381865afa158015611c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2e91906156bd565b60ff1661408f565b604051631cb0f60760e01b815260ff87166004820152611c89907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631cb0f60790602401611bed565b611c958660ff1661408f565b604051635693cc8d60e01b815260ff88166004820152611ce8907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635693cc8d90602401611bed565b604051631cb0f60760e01b815260ff89166004820152611d3b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631cb0f60790602401611bed565b604051602001611d52989796959493929190615994565b604051602081830303815290604052805190602001209350505050919050565b60108161052e8110611d8357600080fd5b015460ff80821692506101009091041682565b610541546001600160a01b03163314611df15760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920564f52436f6f7264696e61746f722063616e2066756c66696c6c006044820152606401610dc4565b61194b828261419d565b606060018054610ccc90615625565b336001600160a01b03831603611e625760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610dc4565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600080611edd610a3784611a83565b60ff16905080600103611ef557610545549150611321565b600060a9611f04836064615a39565b611f0e9190615a58565b611f199060646155f2565b9050600a8110611f295780611f2c565b600a5b905060648161054554611f3f9190615a39565b611f499190615a58565b949350505050565b6000808211611f61576001611f63565b815b905061054454431015611fa65760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd081cdd185c9d195960aa1b6044820152606401610dc4565b61052e611fb260085490565b10611fea5760405162461bcd60e51b81526020600482015260086024820152671cdbdb19081bdd5d60c21b6044820152606401610dc4565b600c5442106120235760405162461bcd60e51b8152602060048201526005602482015264195b99195960da1b6044820152606401610dc4565b610543548111156120655760405162461bcd60e51b815260206004820152600c60248201526b07c40dac2f040e0cae440e8f60a31b6044820152606401610dc4565b6105435481612073336119c6565b61207d9190615952565b11156120ba5760405162461bcd60e51b815260206004820152600c60248201526b0f881b5a5b9d081b1a5b5a5d60a21b6044820152606401610dc4565b61052e816120c760085490565b6120d19190615952565b11156121105760405162461bcd60e51b815260206004820152600e60248201526d6578636565647320737570706c7960901b6044820152606401610dc4565b600061211a614208565b9050670de0b6b3a7640000810560006121338483615a39565b9050803410156121735760405162461bcd60e51b815260206004820152600b60248201526a65746820746f6f206c6f7760a81b6044820152606401610dc4565b60005b848110156121a857600061218960085490565b90506121953382614023565b50806121a081615a6c565b915050612176565b506121b38385614285565b5050505050565b6121c43383613d85565b6121e05760405162461bcd60e51b8152600401610dc4906157d4565b6117a0848484846142c6565b60608161052e8161ffff16106122145760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166122365760405162461bcd60e51b8152600401610dc490615681565b6000612243846001612ade565b905060008061225186612885565b6040516362f4612560e01b815260ff8316600482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906362f4612590602401600060405180830381865afa1580156122bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122e591908101906156da565b6040516362f4612560e01b815260ff831660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906362f4612590602401600060405180830381865afa15801561234c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261237491908101906156da565b8460405160200161238793929190615a85565b604051602081830303815290604052945050505050919050565b6000806123ac614208565b670de0b6b3a7640000900592915050565b606060006123ca83611a83565b905060006123d782612517565b905060006123e6836000612ade565b905060006123f3846121ec565b90506000612403611c2e8661247f565b9050600061244d856124168686866142f9565b6124276124228a610efe565b614328565b60405160200161243993929190615ac8565b604051602081830303815290604052614328565b90506000816040516020016124629190615ba0565b60408051601f198184030181529190529998505050505050505050565b60008161052e8161ffff16106124a75760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166124c95760405162461bcd60e51b8152600401610dc490615681565b61054060006124d7856121ec565b6040516020016124e79190615be5565b60408051808303601f190181529181528151602092830120835290820192909252016000205460ff169392505050565b60608161052e8161ffff161061253f5760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166125615760405162461bcd60e51b8152600401610dc490615681565b60008061256d85612885565b604051633237cc2160e11b815260ff8316600482015291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063646f984290602401600060405180830381865afa1580156125d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261260191908101906156da565b604051633237cc2160e11b815260ff831660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063646f984290602401600060405180830381865afa158015612668573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261269091908101906156da565b6040516020016126a1929190615c11565b6040516020818303038152906040529350505050919050565b600a546001600160a01b031633146126e45760405162461bcd60e51b8152600401610dc49061579f565b600b54156127045760405162461bcd60e51b8152600401610dc490615c37565b600d5460ff166127265760405162461bcd60e51b8152600401610dc490615681565b600e5460ff61273582436155f2565b1115612749576127466001436155f2565b90505b804061275481614492565b600b546040805160008082526020820152908101919091527fad7e9c69b0cb3a7ac544ede8f700bb897c8ee8ea84069062d1a7819e364f439f906060015b60405180910390a15050565b600f80546127ab90615625565b80601f01602080910402602001604051908101604052809291908181526020018280546127d790615625565b80156128245780601f106127f957610100808354040283529160200191612824565b820191906000526020600020905b81548152906001019060200180831161280757829003601f168201915b505050505081565b600a546001600160a01b031633146128565760405162461bcd60e51b8152600401610dc49061579f565b60405133904780156108fc02916000818181858888f19350505050158015612882573d6000803e3d6000fd5b50565b6000808261052e8161ffff16106128ae5760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166128d05760405162461bcd60e51b8152600401610dc490615681565b600060108561ffff1661052e81106128ea576128ea6156a7565b018054604051635693cc8d60e01b815261010090910460ff1660048201529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635693cc8d90602401602060405180830381865afa15801561295c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298091906156bd565b8154604051635693cc8d60e01b815260ff91821660048201529116907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635693cc8d90602401602060405180830381865afa1580156129ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1191906156bd565b60ff161115612a30575460ff8082169450610100909104169150612a40565b5460ff6101008204811694501691505b50915091565b600a546001600160a01b03163314612a705760405162461bcd60e51b8152600401610dc49061579f565b6001600160a01b038116612ad55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610dc4565b6128828161403d565b60608261052e8161ffff1610612b065760405162461bcd60e51b8152600401610dc490615659565b600d5460ff16612b285760405162461bcd60e51b8152600401610dc490615681565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635693cc8d60108761ffff1661052e8110612b7157612b716156a7565b015460405160e083901b6001600160e01b031916815260ff9091166004820152602401602060405180830381865afa158015612bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd591906156bd565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635693cc8d60108861ffff1661052e8110612c2057612c206156a7565b015460405160e083901b6001600160e01b031916815261010090910460ff166004820152602401602060405180830381865afa158015612c64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8891906156bd565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631cb0f60760108961ffff1661052e8110612cd357612cd36156a7565b015460405160e083901b6001600160e01b031916815260ff9091166004820152602401602060405180830381865afa158015612d13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3791906156bd565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631cb0f60760108a61ffff1661052e8110612d8257612d826156a7565b015460405160e083901b6001600160e01b031916815261010090910460ff166004820152602401602060405180830381865afa158015612dc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dea91906156bd565b90508260ff168460ff1603612e3c5786612e2057604051806040016040528060048152602001632830b4b960e11b815250612e31565b604051806020016040528060008152505b955050505050612ee2565b8060ff168260ff1603612e975786612e72576040518060400160405280600681526020016514dd5a5d195960d21b815250612e31565b604051806040016040528060018152602001607360f81b815250955050505050612ee2565b86612ec1576040518060400160405280600781526020016613d9999cdd5a5d60ca1b815250612e31565b604051806040016040528060018152602001606f60f81b8152509550505050505b5092915050565b600a546001600160a01b03163314612f135760405162461bcd60e51b8152600401610dc49061579f565b600d54610100900460ff1615612f565760405162461bcd60e51b81526020600482015260086024820152671d5c1b1bd859195960c21b6044820152606401610dc4565b60005b82518160ff161015612fdd57818160ff1681518110612f7a57612f7a6156a7565b60200260200101516105406000858460ff1681518110612f9c57612f9c6156a7565b6020026020010151815260200190815260200160002060006101000a81548160ff021916908360ff1602179055508080612fd5906158aa565b915050612f59565b50600d805461ff0019166101001790556040517fb41671ac5b828fa53649b0a11eed2c724fdd89d0e768c0ed3873dcffa25dea1690600090a15050565b600a546001600160a01b031633146130445760405162461bcd60e51b8152600401610dc49061579f565b600b54156130645760405162461bcd60e51b8152600401610dc490615c37565b600d5460ff166130865760405162461bcd60e51b8152600401610dc490615681565b61308f816144d0565b5060006130a883836130a2600a436155f2565b406145be565b604080518281523360208201529192507f7efa1de94fe9a97d0a9b97e14bf9ad9c1e6d44837f53c3f742199c0f02c9f50d910160405180910390a1505050565b60007809392ee8e921d5d073aff322e62439fcf32d7f344649470f8f198212156131285760405163e608e18b60e01b815260048101839052602401610dc4565b7809392ee8e921d5d073aff322e62439fcf32d7f344649470f90821315613165576040516371f72a3160e01b815260048101839052602401610dc4565b50670de0b6b3a76400000290565b6000600160ff1b83148061318a5750600160ff1b82145b156131a85760405163b3c754a360e01b815260040160405180910390fd5b600080600085126131b957846131be565b846000035b9150600084126131ce57836131d3565b836000035b905060006131ea83670de0b6b3a76400008461328e565b90506001600160ff1b0381111561321757604051637cb4bef560e01b815260048101829052602401610dc4565b6000198087139086138082186001146132305782613239565b61323983615609565b98975050505050505050565b60008260000361326d57811561325c576000613266565b670de0b6b3a76400005b9050610c38565b61328761328261327c856146cb565b84613c55565b6147b0565b9392505050565b60008080600019858709858702925082811083820303915050806000036132c8578382816132be576132be61596a565b0492505050613287565b8381106132f257604051631dcf306360e21b81526004810182905260248101859052604401610dc4565b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000600160801b821061337a57608091821c916133779082615952565b90505b68010000000000000000821061339d57604091821c9161339a9082615952565b90505b64010000000082106133bc57602091821c916133b99082615952565b90505b6201000082106133d957601091821c916133d69082615952565b90505b61010082106133f557600891821c916133f29082615952565b90505b6010821061341057600491821c9161340d9082615952565b90505b6004821061342b57600291821c916134289082615952565b90505b6002821061343e57610c38600182615952565b919050565b60008080600019848609848602925082811083820303915050670de0b6b3a764000081106134875760405163698d9a0160e11b815260048101829052602401610dc4565b600080670de0b6b3a764000086880991506706f05b59d3b1ffff82119050826000036134c55780670de0b6b3a7640000850401945050505050610c38565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b600160bf1b67800000000000000082161561352d5768016a09e667f3bcc9090260401c5b67400000000000000082161561354c576801306fe0a31b7152df0260401c5b67200000000000000082161561356b576801172b83c7d517adce0260401c5b67100000000000000082161561358a5768010b5586cf9890f62a0260401c5b6708000000000000008216156135a9576801059b0d31585743ae0260401c5b6704000000000000008216156135c857680102c9a3e778060ee70260401c5b6702000000000000008216156135e75768010163da9fb33356d80260401c5b67010000000000000082161561360657680100b1afa5abcbed610260401c5b66800000000000008216156136245768010058c86da1c09ea20260401c5b6640000000000000821615613642576801002c605e2e8cec500260401c5b662000000000000082161561366057680100162f3904051fa10260401c5b661000000000000082161561367e576801000b175effdc76ba0260401c5b660800000000000082161561369c57680100058ba01fb9f96d0260401c5b66040000000000008216156136ba5768010002c5cc37da94920260401c5b66020000000000008216156136d8576801000162e525ee05470260401c5b66010000000000008216156136f65768010000b17255775c040260401c5b65800000000000821615613713576801000058b91b5bc9ae0260401c5b6540000000000082161561373057680100002c5c89d5ec6d0260401c5b6520000000000082161561374d5768010000162e43f4f8310260401c5b6510000000000082161561376a57680100000b1721bcfc9a0260401c5b650800000000008216156137875768010000058b90cf1e6e0260401c5b650400000000008216156137a4576801000002c5c863b73f0260401c5b650200000000008216156137c157680100000162e430e5a20260401c5b650100000000008216156137de576801000000b1721835510260401c5b6480000000008216156137fa57680100000058b90c0b490260401c5b6440000000008216156138165768010000002c5c8601cc0260401c5b642000000000821615613832576801000000162e42fff00260401c5b64100000000082161561384e5768010000000b17217fbb0260401c5b64080000000082161561386a576801000000058b90bfce0260401c5b64040000000082161561388657680100000002c5c85fe30260401c5b6402000000008216156138a25768010000000162e42ff10260401c5b6401000000008216156138be57680100000000b17217f80260401c5b63800000008216156138d95768010000000058b90bfc0260401c5b63400000008216156138f4576801000000002c5c85fe0260401c5b632000000082161561390f57680100000000162e42ff0260401c5b631000000082161561392a576801000000000b17217f0260401c5b630800000082161561394557680100000000058b90c00260401c5b63040000008216156139605768010000000002c5c8600260401c5b630200000082161561397b576801000000000162e4300260401c5b63010000008216156139965768010000000000b172180260401c5b628000008216156139b0576801000000000058b90c0260401c5b624000008216156139ca57680100000000002c5c860260401c5b622000008216156139e45768010000000000162e430260401c5b621000008216156139fe57680100000000000b17210260401c5b62080000821615613a185768010000000000058b910260401c5b62040000821615613a32576801000000000002c5c80260401c5b62020000821615613a4c57680100000000000162e40260401c5b62010000821615613a66576801000000000000b1720260401c5b618000821615613a7f57680100000000000058b90260401c5b614000821615613a985768010000000000002c5d0260401c5b612000821615613ab1576801000000000000162e0260401c5b611000821615613aca5768010000000000000b170260401c5b610800821615613ae3576801000000000000058c0260401c5b610400821615613afc57680100000000000002c60260401c5b610200821615613b1557680100000000000001630260401c5b610100821615613b2e57680100000000000000b10260401c5b6080821615613b4657680100000000000000590260401c5b6040821615613b5e576801000000000000002c0260401c5b6020821615613b7657680100000000000000160260401c5b6010821615613b8e576801000000000000000b0260401c5b6008821615613ba657680100000000000000060260401c5b6004821615613bbe57680100000000000000030260401c5b6002821615613bd657680100000000000000010260401c5b6001821615613bee57680100000000000000010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b60006001600160e01b031982166380ac58cd60e01b1480613c3657506001600160e01b03198216635b5e139f60e01b145b80610c3857506301ffc9a760e01b6001600160e01b0319831614610c38565b6000600160ff1b831480613c6c5750600160ff1b82145b15613c8a57604051630d01a11b60e21b815260040160405180910390fd5b60008060008512613c9b5784613ca0565b846000035b915060008412613cb05783613cb5565b836000035b90506000613cc38383613443565b90506001600160ff1b03811115613cf05760405163bf79e8d960e01b815260048101829052602401610dc4565b600019808713908613808218600114613d095782613239565b505060000395945050505050565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190613d4c8261194f565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b0316613dfe5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610dc4565b6000613e098361194f565b9050806001600160a01b0316846001600160a01b03161480613e445750836001600160a01b0316613e3984610d4f565b6001600160a01b0316145b80611f4957506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff16611f49565b826001600160a01b0316613e8b8261194f565b6001600160a01b031614613ef35760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610dc4565b6001600160a01b038216613f555760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610dc4565b613f60838383614848565b613f6b600082613d17565b6001600160a01b0383166000908152600360205260408120805460019290613f949084906155f2565b90915550506001600160a01b0382166000908152600360205260408120805460019290613fc2908490615952565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61194b828260405180602001604052806000815250614900565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60608160008190036140ba5750506040805180820190915260018152600360fc1b6020820152919050565b8060005b81156140e457806140ce81615a6c565b91506140dd9050600a83615a58565b91506140be565b60008167ffffffffffffffff8111156140ff576140ff615115565b6040519080825280601f01601f191660200182016040528015614129576020820181803683370190505b5090505b83156141945761413e6001836155f2565b915061414b600a85615980565b614156906030615952565b60f81b81838151811061416b5761416b6156a7565b60200101906001600160f81b031916908160001a90535061418d600a85615a58565b935061412d565b95945050505050565b600b54156141bd5760405162461bcd60e51b8152600401610dc490615c37565b6141c681614492565b600b546040805184815260208101849052908101919091527fad7e9c69b0cb3a7ac544ede8f700bb897c8ee8ea84069062d1a7819e364f439f90606001612792565b600061054754431161421c57506105495490565b6000614235610547544361423091906155f2565b6130e8565b9050600061427461426f7f000000000000000000000000000000000000000000000000000000000000000061426985615609565b90613173565b614933565b61054954909150610cb69082613c55565b61428e816130e8565b614296610c3e565b6142a09190615911565b610548556142ad826117c1565b610549556142b96149a3565b6105475550504361054655565b6142d1848484613e78565b6142dd84848484614a51565b6117a05760405162461bcd60e51b8152600401610dc490615c5d565b606083838360405160200161431093929190615caf565b60405160208183030381529060405290509392505050565b8051606090600081900361434c575050604080516020810190915260008152919050565b6000600361435b836002615952565b6143659190615a58565b614370906004615a39565b9050600061437f826020615952565b67ffffffffffffffff81111561439757614397615115565b6040519080825280601f01601f1916602001820160405280156143c1576020820181803683370190505b5090506000604051806060016040528060408152602001615eda604091399050600181016020830160005b8681101561444d576003818a01810151603f601282901c8116860151600c83901c8216870151600684901c831688015192909316870151600891821b60ff94851601821b92841692909201901b91160160e01b8352600490920191016143ec565b506003860660018114614467576002811461447857614484565b613d3d60f01b600119830152614484565b603d60f81b6000198301525b505050918152949350505050565b61449f600161052e6155f2565b6144a99082615980565b600b8190556000036144bb576001600b555b61052d600b5411156128825761052d600b5550565b61054154604051633950935160e01b81526001600160a01b039182166004820152602481018390526000917f000000000000000000000000000000000000000000000000000000000000000016906339509351906044016020604051808303816000875af1158015614546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061456a9190615dc7565b6145b65760405162461bcd60e51b815260206004820152601c60248201527f6661696c656420746f20696e63726561736520616c6c6f77616e6365000000006044820152606401610dc4565b506001919050565b6105415460405163264eb1cf60e01b81526004810185905260248101839052604481018490526000916001600160a01b03169063264eb1cf90606401600060405180830381600087803b15801561461457600080fd5b505af1158015614628573d6000803e3d6000fd5b5050506000858152610542602081815260408084205481518084018b905280830189905230606082015260808082018390528351808303909101815260a09091019092528151918301919091209389905291905290915061468a906001614b52565b600086815261054260205260409020556141948582604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b60008082136146f05760405163309fa7dd60e11b815260048101839052602401610dc4565b6000670de0b6b3a7640000831261470957506001614723565b6000199050826ec097ce7bc90715b34b9f10000000000492505b6000614738670de0b6b3a7640000850561335a565b670de0b6b3a764000081029350905083811d670de0b6b3a763ffff19810161476257505002919050565b6706f05b59d3b200005b60008113156147a757670de0b6b3a7640000828002059150671bc16d674ec80000821261479f579384019360019190911d905b60011d61476c565b50505002919050565b6000808212156148045768033dd1780914b97114198212156147d457506000919050565b6147e0826000036147b0565b6ec097ce7bc90715b34b9f1000000000816147fd576147fd61596a565b0592915050565b680a688906bd8b00000082126148305760405163e69458f960e01b815260048101839052602401610dc4565b670de0b6b3a7640000604083901b0461328781613509565b6001600160a01b0383166148a35761489e81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6148c6565b816001600160a01b0316836001600160a01b0316146148c6576148c68382614bb1565b6001600160a01b0382166148dd57610ef981614c4e565b826001600160a01b0316826001600160a01b031614610ef957610ef98282614cfd565b61490a8383614d41565b6149176000848484614a51565b610ef95760405162461bcd60e51b8152600401610dc490615c5d565b600068023f2fa8f6da5b9d311982121561494f57506000919050565b680736ea4425c11ac631821261497b576040516399bb754160e01b815260048101839052602401610dc4565b6714057b7ef767814f8202613287670de0b6b3a76400006706f05b59d3b200008301056147b0565b6000806149dc7f00000000000000000000000000000000000000000000000000000000000000006105485461317390919063ffffffff16565b90506149e860016130e8565b811315614a49576000614a3d614a2f614a2a614a03856146cb565b7f000000000000000000000000000000000000000000000000000000000000000090613c55565b614e8f565b670de0b6b3a7640000900590565b9050610cb68143615952565b4391505b5090565b60006001600160a01b0384163b15614b4757604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614a95903390899088908890600401615de4565b6020604051808303816000875af1925050508015614ad0575060408051601f3d908101601f19168201909252614acd91810190615e21565b60015b614b2d573d808015614afe576040519150601f19603f3d011682016040523d82523d6000602084013e614b03565b606091505b508051600003614b255760405162461bcd60e51b8152600401610dc490615c5d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611f49565b506001949350505050565b600080614b5f8385615952565b9050838110156132875760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610dc4565b60006001614bbe846119c6565b614bc891906155f2565b600083815260076020526040902054909150808214614c1b576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090614c60906001906155f2565b60008381526009602052604081205460088054939450909284908110614c8857614c886156a7565b906000526020600020015490508060088381548110614ca957614ca96156a7565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480614ce157614ce1615e3e565b6001900381819060005260206000200160009055905550505050565b6000614d08836119c6565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6001600160a01b038216614d975760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610dc4565b6000818152600260205260409020546001600160a01b031615614dfc5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610dc4565b614e0860008383614848565b6001600160a01b0382166000908152600360205260408120805460019290614e31908490615952565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000670afdc366fbc00000600160ff1b03821315614ec357604051635399a28560e11b815260048101839052602401610dc4565b670de0b6b3a764000082076000819003614edf57829150611321565b808303915060008313156113215750670de0b6b3a764000001919050565b60405180608001604052806004905b6060815260200190600190039081614f0c5790505090565b828054614f3090615625565b90600052602060002090601f016020900481019282614f525760008555614f98565b82601f10614f6b57805160ff1916838001178555614f98565b82800160010185558215614f98579182015b82811115614f98578251825591602001919060010190614f7d565b50614a4d9291505b80821115614a4d5760008155600101614fa0565b6001600160e01b03198116811461288257600080fd5b600060208284031215614fdc57600080fd5b813561328781614fb4565b60005b83811015615002578181015183820152602001614fea565b838111156117a05750506000910152565b6000815180845261502b816020860160208601614fe7565b601f01601f19169290920160200192915050565b6020815260006132876020830184615013565b60006020828403121561506457600080fd5b5035919050565b80356001600160a01b038116811461343e57600080fd5b6000806040838503121561509557600080fd5b61509e8361506b565b946020939093013593505050565b803561ffff8116811461343e57600080fd5b6000602082840312156150d057600080fd5b613287826150ac565b6000806000606084860312156150ee57600080fd5b6150f78461506b565b92506151056020850161506b565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561514e5761514e615115565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561517d5761517d615115565b604052919050565b600067ffffffffffffffff82111561519f5761519f615115565b5060051b60200190565b60ff8116811461288257600080fd5b803561343e816151a9565b600067ffffffffffffffff8211156151dd576151dd615115565b50601f01601f191660200190565b60006151fe6151f9846151c3565b615154565b905082815283838301111561521257600080fd5b828260208301376000602084830101529392505050565b600082601f83011261523a57600080fd5b613287838335602085016151eb565b60008060006060848603121561525e57600080fd5b833567ffffffffffffffff8082111561527657600080fd5b8186019150601f878184011261528b57600080fd5b8235602061529b6151f983615185565b82815260069290921b8501810191818101908b8411156152ba57600080fd5b958201955b83871015615328578b858801126152d65760008081fd5b6152de61512b565b80604089018e8111156152f15760008081fd5b895b81811015615313578035615306816151a9565b84529286019286016152f3565b505083525060409690960195908201906152bf565b985061533790508982016151b8565b9650505050604086013591508082111561535057600080fd5b5061535d86828701615229565b9150509250925092565b60006020828403121561537957600080fd5b6132878261506b565b6000806040838503121561539557600080fd5b50508035926020909101359150565b801515811461288257600080fd5b600080604083850312156153c557600080fd5b6153ce8361506b565b915060208301356153de816153a4565b809150509250929050565b600080600080608085870312156153ff57600080fd5b6154088561506b565b93506154166020860161506b565b925060408501359150606085013567ffffffffffffffff81111561543957600080fd5b8501601f8101871361544a57600080fd5b615459878235602084016151eb565b91505092959194509250565b6000806040838503121561547857600080fd5b6154818361506b565b915061548f6020840161506b565b90509250929050565b600080604083850312156154ab57600080fd5b6153ce836150ac565b600082601f8301126154c557600080fd5b813560206154d56151f983615185565b82815260059290921b840181019181810190868411156154f457600080fd5b8286015b8481101561551857803561550b816151a9565b83529183019183016154f8565b509695505050505050565b6000806040838503121561553657600080fd5b823567ffffffffffffffff8082111561554e57600080fd5b818501915085601f83011261556257600080fd5b813560206155726151f983615185565b82815260059290921b8401810191818101908984111561559157600080fd5b948201945b838610156155af57853582529482019490820190615596565b965050860135925050808211156155c557600080fd5b506155d2858286016154b4565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b600082821015615604576156046155dc565b500390565b6000600160ff1b820161561e5761561e6155dc565b5060000390565b600181811c9082168061563957607f821691505b60208210810361132157634e487b7160e01b600052602260045260246000fd5b6020808252600e908201526d1a5b9d985b1a59081a185b99125960921b604082015260600190565b6020808252600c908201526b1b9bdd081c995d99585b195960a21b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156156cf57600080fd5b8151613287816151a9565b6000602082840312156156ec57600080fd5b815167ffffffffffffffff81111561570357600080fd5b8201601f8101841361571457600080fd5b80516157226151f9826151c3565b81815285602083850101111561573757600080fd5b614194826020830160208601614fe7565b6000855161575a818460208a01614fe7565b85519083019061576e818360208a01614fe7565b8551910190615781818360208901614fe7565b8451910190615794818360208801614fe7565b019695505050505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b81516000908290602080860184805b8481101561587757825186835b600281101561586157825160ff1682529186019190860190600101615841565b5050506040959095019491830191600101615834565b5093979650505050505050565b600061ffff8083168185168083038211156158a1576158a16155dc565b01949350505050565b600060ff821660ff81036158c0576158c06155dc565b60010192915050565b600061ffff838116908316818110156158e4576158e46155dc565b039392505050565b600060ff821660ff84168060ff03821115615909576159096155dc565b019392505050565b600080821280156001600160ff1b0384900385131615615933576159336155dc565b600160ff1b839003841281161561594c5761594c6155dc565b50500190565b60008219821115615965576159656155dc565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261598f5761598f61596a565b500690565b6000895160206159a78285838f01614fe7565b8a51918401916159ba8184848f01614fe7565b8a519201916159cc8184848e01614fe7565b89519201916159de8184848d01614fe7565b88519201916159f08184848c01614fe7565b8751920191615a028184848b01614fe7565b8651920191615a148184848a01614fe7565b8551920191615a268184848901614fe7565b919091019b9a5050505050505050505050565b6000816000190483118215151615615a5357615a536155dc565b500290565b600082615a6757615a6761596a565b500490565b600060018201615a7e57615a7e6155dc565b5060010190565b60008451615a97818460208901614fe7565b845190830190615aab818360208901614fe7565b8451910190615abe818360208801614fe7565b0195945050505050565b693d913730b6b2911d101160b11b81528351600090615aee81600a850160208901614fe7565b7f222c20226465736372697074696f6e223a2022686f6c64656d6865726f65732e600a918401918201526418dbdb488b60da1b602a8201528451615b3981602f840160208901614fe7565b7f22696d616765223a2022646174613a696d6167652f7376672b786d6c3b626173602f929091019182015263194d8d0b60e21b604f8201528351615b84816053840160208801614fe7565b61227d60f01b6053929091019182015260550195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251615bd881601d850160208701614fe7565b91909101601d0192915050565b6372616e6b60e01b815260008251615c04816004850160208701614fe7565b9190910160040192915050565b60008351615c23818460208801614fe7565b8351908301906158a1818360208801614fe7565b6020808252600c908201526b616c726561647920646f6e6560a01b604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b7f2261747472696275746573223a205b7b202274726169745f74797065223a202281527129b430b832911610113b30b63ab2911d101160711b602082015260008451615d02816032850160208901614fe7565b62089f4b60ea1b60329184019182018190527f7b202274726169745f74797065223a202248616e64222c202276616c7565223a603583015261101160f11b605583018190528651615d5a816057860160208b01614fe7565b60579301928301919091527f7b202274726169745f74797065223a202252616e6b222c202276616c7565223a605a830152607a8201528351615da381607c840160208801614fe7565b615dbc607c8284010163089f574b60e21b815260040190565b979650505050505050565b600060208284031215615dd957600080fd5b8151613287816153a4565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e1790830184615013565b9695505050505050565b600060208284031215615e3357600080fd5b815161328781614fb4565b634e487b7160e01b600052603160045260246000fdfe3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f7376672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f313939392f786c696e6b222076696577426f783d2230203020313438203632222077696474683d2235696e22206865696768743d22322e313437696e223e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212202368e0dc7711ed437a6113708eefa64ae68ccb1c529d3cb7b5d18ec918aec2ad64736f6c634300080d0033000000000000000000000000ceb679de692660dd701837c25a4181492050ed8f000000000000000000000000892a6f9df0147e5f079b0993f486f9aca3c87881000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e0000000000000000000000000000000000000000000000000000000000df1e5c00000000000000000000000000000000000000000000000000000000626406600000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c4000000000000000000000000000000000000000000000000016345785d8a0000

Deployed Bytecode

0x6080604052600436106103c35760003560e01c80638e6afff9116101f2578063c97513431161010d578063df1cb687116100a0578063f2fde38b1161006f578063f2fde38b14610b93578063f3231e4314610bb3578063f67a35df14610bd3578063fc19521e14610bf357600080fd5b8063df1cb68714610ae1578063e086e5ec14610b15578063e985e9c514610b2a578063efa6dba214610b7357600080fd5b8063d480c928116100dc578063d480c92814610a89578063d8328d3214610a9e578063da41672f14610ab5578063defadae114610acc57600080fd5b8063c975134314610a1c578063cb774d4714610a3c578063cb96e2b014610a52578063cee2b67714610a6957600080fd5b8063a76a958711610185578063c2a99f5d11610154578063c2a99f5d14610993578063c4108ccd146109b3578063c4912774146109e7578063c87b56dd146109fc57600080fd5b8063a76a958714610930578063b5077f441461094a578063b846a2b414610960578063b88d4fde1461097357600080fd5b8063a17716ac116101c1578063a17716ac146108c2578063a22cb465146108d9578063a27e5487146108f9578063a6f593751461091057600080fd5b80638e6afff91461081f57806394985ddd1461085957806395d89b411461087957806396d4fc201461088e57600080fd5b806346551621116102e25780636233e31811610275578063715018a611610244578063715018a6146107ac57806372fca5d0146107c157806386f84119146107e15780638da5cb5b1461080157600080fd5b80636233e318146107225780636352211e1461075657806366bb81c71461077657806370a082311461078c57600080fd5b80634eebd25f116102b15780634eebd25f1461068a5780634f6ccce7146106be578063544df5b1146106de57806356f02b261461070f57600080fd5b806346551621146105f0578063468fe8481461061f57806346a763701461063f57806349a0088f1461065657600080fd5b806314665ce81161035a5780632f745c59116103295780632f745c591461055d5780632ff46f9d1461057d57806332868c2f146105b057806342842e0e146105d057600080fd5b806314665ce8146104f257806318160ddd1461051257806318e20a381461052757806323b872dd1461053d57600080fd5b8063081812fc11610396578063081812fc14610459578063095ea7b3146104915780630d18b702146104b35780630fbec443146104d357600080fd5b806301ffc9a7146103c857806305c8c51f146103fd57806306e32b641461042257806306fdde0314610437575b600080fd5b3480156103d457600080fd5b506103e86103e3366004614fca565b610c13565b60405190151581526020015b60405180910390f35b34801561040957600080fd5b506104146105465481565b6040519081526020016103f4565b34801561042e57600080fd5b50610414610c3e565b34801561044357600080fd5b5061044c610cbd565b6040516103f4919061503f565b34801561046557600080fd5b50610479610474366004615052565b610d4f565b6040516001600160a01b0390911681526020016103f4565b34801561049d57600080fd5b506104b16104ac366004615082565b610de9565b005b3480156104bf57600080fd5b5061044c6104ce3660046150be565b610efe565b3480156104df57600080fd5b50600d546103e890610100900460ff1681565b3480156104fe57600080fd5b506104b161050d366004615052565b611327565b34801561051e57600080fd5b50600854610414565b34801561053357600080fd5b50610414600c5481565b34801561054957600080fd5b506104b16105583660046150d9565b611357565b34801561056957600080fd5b50610414610578366004615082565b611388565b34801561058957600080fd5b5061053e5461059e9062010000900460ff1681565b60405160ff90911681526020016103f4565b3480156105bc57600080fd5b506104b16105cb366004615249565b61141e565b3480156105dc57600080fd5b506104b16105eb3660046150d9565b6117a6565b3480156105fc57600080fd5b5061053e5461060c9061ffff1681565b60405161ffff90911681526020016103f4565b34801561062b57600080fd5b5061041461063a366004615052565b6117c1565b34801561064b57600080fd5b506104146105495481565b34801561066257600080fd5b506104147fbcd1a23f7cca99ec419590e58d82db68573d59d2cdf88a901c5c25edea2c075d81565b34801561069657600080fd5b506104147f0000000000000000000000000000000000000000000000011f4bc49a7eaf5cbe81565b3480156106ca57600080fd5b506104146106d9366004615052565b611863565b3480156106ea57600080fd5b5061059e6106f9366004615052565b6105406020526000908152604090205460ff1681565b6104b161071d366004615052565b6118f6565b34801561072e57600080fd5b506104797f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e81565b34801561076257600080fd5b50610479610771366004615052565b61194f565b34801561078257600080fd5b50610414600e5481565b34801561079857600080fd5b506104146107a7366004615367565b6119c6565b3480156107b857600080fd5b506104b1611a4d565b3480156107cd57600080fd5b5061060c6107dc366004615052565b611a83565b3480156107ed57600080fd5b506104146107fc3660046150be565b611b22565b34801561080d57600080fd5b50600a546001600160a01b0316610479565b34801561082b57600080fd5b5061083f61083a366004615052565b611d72565b6040805160ff9384168152929091166020830152016103f4565b34801561086557600080fd5b506104b1610874366004615382565b611d96565b34801561088557600080fd5b5061044c611dfb565b34801561089a57600080fd5b506104147f00000000000000000000000000000000000000000000000aa00be18c2890000081565b3480156108ce57600080fd5b506104146105485481565b3480156108e557600080fd5b506104b16108f43660046153b2565b611e0a565b34801561090557600080fd5b506104146105435481565b34801561091c57600080fd5b5061041461092b366004615052565b611ece565b34801561093c57600080fd5b50600d546103e89060ff1681565b34801561095657600080fd5b5061041461052e81565b6104b161096e366004615052565b611f51565b34801561097f57600080fd5b506104b161098e3660046153e9565b6121ba565b34801561099f57600080fd5b5061044c6109ae3660046150be565b6121ec565b3480156109bf57600080fd5b506104147f00000000000000000000000000000000000000000000000003782dace9d9000081565b3480156109f357600080fd5b506104146123a1565b348015610a0857600080fd5b5061044c610a17366004615052565b6123bd565b348015610a2857600080fd5b5061059e610a373660046150be565b61247f565b348015610a4857600080fd5b50610414600b5481565b348015610a5e57600080fd5b506104146105455481565b348015610a7557600080fd5b5061044c610a843660046150be565b612517565b348015610a9557600080fd5b506104b16126ba565b348015610aaa57600080fd5b506104146105445481565b348015610ac157600080fd5b506104146105475481565b348015610ad857600080fd5b5061044c61279e565b348015610aed57600080fd5b506104147f00000000000000000000000000000000000000000000000aa00be18c2890000081565b348015610b2157600080fd5b506104b161282c565b348015610b3657600080fd5b506103e8610b45366004615465565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b348015610b7f57600080fd5b5061083f610b8e3660046150be565b612885565b348015610b9f57600080fd5b506104b1610bae366004615367565b612a46565b348015610bbf57600080fd5b5061044c610bce366004615498565b612ade565b348015610bdf57600080fd5b506104b1610bee366004615523565b612ee9565b348015610bff57600080fd5b506104b1610c0e366004615382565b61301a565b60006001600160e01b0319821663780e9d6360e01b1480610c385750610c3882613c05565b92915050565b6000806105465443610c5091906155f2565b9050610c5b816130e8565b90506000610ca5610c8c837f00000000000000000000000000000000000000000000000aa00be18c28900000613173565b610c9590615609565b610c9f60026130e8565b90613245565b61054854909150610cb69082613c55565b9250505090565b606060008054610ccc90615625565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf890615625565b8015610d455780601f10610d1a57610100808354040283529160200191610d45565b820191906000526020600020905b815481529060010190602001808311610d2857829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b0316610dcd5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000610df48261194f565b9050806001600160a01b0316836001600160a01b031603610e615760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610dc4565b336001600160a01b0382161480610e7d5750610e7d8133610b45565b610eef5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610dc4565b610ef98383613d17565b505050565b60608161052e8161ffff1610610f265760405162461bcd60e51b8152600401610dc490615659565b600d5460ff16610f485760405162461bcd60e51b8152600401610dc490615681565b600080610f5485612885565b91509150610f60614efd565b6040518060c0016040528060858152602001615e55608591398152604051635693cc8d60e01b815260ff841660048201526001600160a01b037f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e16906346a0b33e908290635693cc8d90602401602060405180830381865afa158015610fea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100e91906156bd565b604051631cb0f60760e01b815260ff871660048201527f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690631cb0f60790602401602060405180830381865afa158015611075573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109991906156bd565b6040516001600160e01b031960e085901b16815260ff92831660048201529116602482015260076044820152602060648201526002608482015260a401600060405180830381865afa1580156110f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261111b91908101906156da565b6020820152604051635693cc8d60e01b815260ff831660048201526001600160a01b037f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e16906346a0b33e908290635693cc8d90602401602060405180830381865afa15801561118f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b391906156bd565b604051631cb0f60760e01b815260ff861660048201527f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690631cb0f60790602401602060405180830381865afa15801561121a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123e91906156bd565b6040516001600160e01b031960e085901b16815260ff92831660048201529116602482015260526044820152606b6064820152604c608482015260a401600060405180830381865afa158015611298573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c091908101906156da565b60408281019182528051808201825260068152651e17b9bb339f60d11b602080830191909152606085018290528451818601519451935160009561130a9592949093909101615748565b60408051601f198184030181529190529550505050505b50919050565b600a546001600160a01b031633146113515760405162461bcd60e51b8152600401610dc49061579f565b61054555565b6113613382613d85565b61137d5760405162461bcd60e51b8152600401610dc4906157d4565b610ef9838383613e78565b6000611393836119c6565b82106113f55760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610dc4565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b600a546001600160a01b031633146114485760405162461bcd60e51b8152600401610dc49061579f565b600c544210156114845760405162461bcd60e51b81526020600482015260076024820152661b9bdd081e595d60ca1b6044820152606401610dc4565b61053e5461052d61ffff909116106114c95760405162461bcd60e51b81526020600482015260086024820152671c995d99585b195960c21b6044820152606401610dc4565b61053e5460ff8381166201000090920416146115175760405162461bcd60e51b815260206004820152600d60248201526c1cd95c481a5b98dbdc9c9958dd609a1b6044820152606401610dc4565b60008360405160200161152a9190615825565b60408051601f198184030181529181528151602092830120600081815261053f90935291205490915060ff16156115935760405162461bcd60e51b815260206004820152600d60248201526c185b1c9958591e481859191959609a1b6044820152606401610dc4565b600081815261053f60205260408120805460ff191660011790555b84518160ff1610156116ba576040518060400160405280868360ff16815181106115da576115da6156a7565b60200260200101516000600281106115f4576115f46156a7565b602002015160ff168152602001868360ff1681518110611616576116166156a7565b6020026020010151600160028110611630576116306156a7565b602002015160ff16905261053e5460109061ffff1661052e8110611656576116566156a7565b82519101805460209093015160ff9081166101000261ffff1990941692169190911791909117905561053e546116919061ffff166001615884565b61053e805461ffff191661ffff92909216919091179055806116b2816158aa565b9150506115ae565b50835161053e547f28164971f0369b47dcecec8a5f7579a452938bd58e9c2e78dd7d4404aba9308c916116f09161ffff166158c9565b61053e546117049060019061ffff166158c9565b6040805161ffff9384168152929091166020830152810183905260ff8516606082015260800160405180910390a161053e5461ffff1661052e0361176c57600d805460ff19166001179055815161176290600f906020850190614f24565b5043600e556117a0565b61053e546117849062010000900460ff1660016158ec565b61053e60026101000a81548160ff021916908360ff1602179055505b50505050565b610ef9838383604051806020016040528060008152506121ba565b6000806117fa7f0000000000000000000000000000000000000000000000011f4bc49a7eaf5cbe6105485461317390919063ffffffff16565b905061180660016130e8565b81131561185c5761185561183a827f00000000000000000000000000000000000000000000000003782dace9d90000613c55565b61184460016130e8565b61184e9190615911565b8490613c55565b9150611321565b5090919050565b600061186e60085490565b82106118d15760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610dc4565b600882815481106118e4576118e46156a7565b90600052602060002001549050919050565b600061190182611ece565b9050803410156119415760405162461bcd60e51b815260206004820152600b60248201526a65746820746f6f206c6f7760a81b6044820152606401610dc4565b61194b3383614023565b5050565b6000818152600260205260408120546001600160a01b031680610c385760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610dc4565b60006001600160a01b038216611a315760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610dc4565b506001600160a01b031660009081526003602052604090205490565b600a546001600160a01b03163314611a775760405162461bcd60e51b8152600401610dc49061579f565b611a81600061403d565b565b600061052e8210611ac35760405162461bcd60e51b815260206004820152600a6024820152691a5b9d985b1a59081a5960b21b6044820152606401610dc4565b6000600b5411611b075760405162461bcd60e51b815260206004820152600f60248201526e1b9bdd08191a5cdd1c9a589d5d1959608a1b6044820152606401610dc4565b61052e600b5483611b189190615952565b610c389190615980565b60008161052e8161ffff1610611b4a5760405162461bcd60e51b8152600401610dc490615659565b600d5460ff16611b6c5760405162461bcd60e51b8152600401610dc490615681565b600080611b7885612885565b91509150611b898561ffff1661408f565b611b9286612517565b611b9e8460ff1661408f565b604051635693cc8d60e01b815260ff86166004820152611c36907f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690635693cc8d906024015b602060405180830381865afa158015611c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2e91906156bd565b60ff1661408f565b604051631cb0f60760e01b815260ff87166004820152611c89907f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690631cb0f60790602401611bed565b611c958660ff1661408f565b604051635693cc8d60e01b815260ff88166004820152611ce8907f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690635693cc8d90602401611bed565b604051631cb0f60760e01b815260ff89166004820152611d3b907f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690631cb0f60790602401611bed565b604051602001611d52989796959493929190615994565b604051602081830303815290604052805190602001209350505050919050565b60108161052e8110611d8357600080fd5b015460ff80821692506101009091041682565b610541546001600160a01b03163314611df15760405162461bcd60e51b815260206004820152601f60248201527f4f6e6c7920564f52436f6f7264696e61746f722063616e2066756c66696c6c006044820152606401610dc4565b61194b828261419d565b606060018054610ccc90615625565b336001600160a01b03831603611e625760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610dc4565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600080611edd610a3784611a83565b60ff16905080600103611ef557610545549150611321565b600060a9611f04836064615a39565b611f0e9190615a58565b611f199060646155f2565b9050600a8110611f295780611f2c565b600a5b905060648161054554611f3f9190615a39565b611f499190615a58565b949350505050565b6000808211611f61576001611f63565b815b905061054454431015611fa65760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd081cdd185c9d195960aa1b6044820152606401610dc4565b61052e611fb260085490565b10611fea5760405162461bcd60e51b81526020600482015260086024820152671cdbdb19081bdd5d60c21b6044820152606401610dc4565b600c5442106120235760405162461bcd60e51b8152602060048201526005602482015264195b99195960da1b6044820152606401610dc4565b610543548111156120655760405162461bcd60e51b815260206004820152600c60248201526b07c40dac2f040e0cae440e8f60a31b6044820152606401610dc4565b6105435481612073336119c6565b61207d9190615952565b11156120ba5760405162461bcd60e51b815260206004820152600c60248201526b0f881b5a5b9d081b1a5b5a5d60a21b6044820152606401610dc4565b61052e816120c760085490565b6120d19190615952565b11156121105760405162461bcd60e51b815260206004820152600e60248201526d6578636565647320737570706c7960901b6044820152606401610dc4565b600061211a614208565b9050670de0b6b3a7640000810560006121338483615a39565b9050803410156121735760405162461bcd60e51b815260206004820152600b60248201526a65746820746f6f206c6f7760a81b6044820152606401610dc4565b60005b848110156121a857600061218960085490565b90506121953382614023565b50806121a081615a6c565b915050612176565b506121b38385614285565b5050505050565b6121c43383613d85565b6121e05760405162461bcd60e51b8152600401610dc4906157d4565b6117a0848484846142c6565b60608161052e8161ffff16106122145760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166122365760405162461bcd60e51b8152600401610dc490615681565b6000612243846001612ade565b905060008061225186612885565b6040516362f4612560e01b815260ff8316600482015291935091507f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b0316906362f4612590602401600060405180830381865afa1580156122bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122e591908101906156da565b6040516362f4612560e01b815260ff831660048201527f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b0316906362f4612590602401600060405180830381865afa15801561234c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261237491908101906156da565b8460405160200161238793929190615a85565b604051602081830303815290604052945050505050919050565b6000806123ac614208565b670de0b6b3a7640000900592915050565b606060006123ca83611a83565b905060006123d782612517565b905060006123e6836000612ade565b905060006123f3846121ec565b90506000612403611c2e8661247f565b9050600061244d856124168686866142f9565b6124276124228a610efe565b614328565b60405160200161243993929190615ac8565b604051602081830303815290604052614328565b90506000816040516020016124629190615ba0565b60408051601f198184030181529190529998505050505050505050565b60008161052e8161ffff16106124a75760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166124c95760405162461bcd60e51b8152600401610dc490615681565b61054060006124d7856121ec565b6040516020016124e79190615be5565b60408051808303601f190181529181528151602092830120835290820192909252016000205460ff169392505050565b60608161052e8161ffff161061253f5760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166125615760405162461bcd60e51b8152600401610dc490615681565b60008061256d85612885565b604051633237cc2160e11b815260ff8316600482015291935091507f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b03169063646f984290602401600060405180830381865afa1580156125d9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261260191908101906156da565b604051633237cc2160e11b815260ff831660048201527f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b03169063646f984290602401600060405180830381865afa158015612668573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261269091908101906156da565b6040516020016126a1929190615c11565b6040516020818303038152906040529350505050919050565b600a546001600160a01b031633146126e45760405162461bcd60e51b8152600401610dc49061579f565b600b54156127045760405162461bcd60e51b8152600401610dc490615c37565b600d5460ff166127265760405162461bcd60e51b8152600401610dc490615681565b600e5460ff61273582436155f2565b1115612749576127466001436155f2565b90505b804061275481614492565b600b546040805160008082526020820152908101919091527fad7e9c69b0cb3a7ac544ede8f700bb897c8ee8ea84069062d1a7819e364f439f906060015b60405180910390a15050565b600f80546127ab90615625565b80601f01602080910402602001604051908101604052809291908181526020018280546127d790615625565b80156128245780601f106127f957610100808354040283529160200191612824565b820191906000526020600020905b81548152906001019060200180831161280757829003601f168201915b505050505081565b600a546001600160a01b031633146128565760405162461bcd60e51b8152600401610dc49061579f565b60405133904780156108fc02916000818181858888f19350505050158015612882573d6000803e3d6000fd5b50565b6000808261052e8161ffff16106128ae5760405162461bcd60e51b8152600401610dc490615659565b600d5460ff166128d05760405162461bcd60e51b8152600401610dc490615681565b600060108561ffff1661052e81106128ea576128ea6156a7565b018054604051635693cc8d60e01b815261010090910460ff1660048201529091507f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690635693cc8d90602401602060405180830381865afa15801561295c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298091906156bd565b8154604051635693cc8d60e01b815260ff91821660048201529116907f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b031690635693cc8d90602401602060405180830381865afa1580156129ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1191906156bd565b60ff161115612a30575460ff8082169450610100909104169150612a40565b5460ff6101008204811694501691505b50915091565b600a546001600160a01b03163314612a705760405162461bcd60e51b8152600401610dc49061579f565b6001600160a01b038116612ad55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610dc4565b6128828161403d565b60608261052e8161ffff1610612b065760405162461bcd60e51b8152600401610dc490615659565b600d5460ff16612b285760405162461bcd60e51b8152600401610dc490615681565b60007f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b0316635693cc8d60108761ffff1661052e8110612b7157612b716156a7565b015460405160e083901b6001600160e01b031916815260ff9091166004820152602401602060405180830381865afa158015612bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd591906156bd565b905060007f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b0316635693cc8d60108861ffff1661052e8110612c2057612c206156a7565b015460405160e083901b6001600160e01b031916815261010090910460ff166004820152602401602060405180830381865afa158015612c64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8891906156bd565b905060007f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b0316631cb0f60760108961ffff1661052e8110612cd357612cd36156a7565b015460405160e083901b6001600160e01b031916815260ff9091166004820152602401602060405180830381865afa158015612d13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3791906156bd565b905060007f000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e6001600160a01b0316631cb0f60760108a61ffff1661052e8110612d8257612d826156a7565b015460405160e083901b6001600160e01b031916815261010090910460ff166004820152602401602060405180830381865afa158015612dc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dea91906156bd565b90508260ff168460ff1603612e3c5786612e2057604051806040016040528060048152602001632830b4b960e11b815250612e31565b604051806020016040528060008152505b955050505050612ee2565b8060ff168260ff1603612e975786612e72576040518060400160405280600681526020016514dd5a5d195960d21b815250612e31565b604051806040016040528060018152602001607360f81b815250955050505050612ee2565b86612ec1576040518060400160405280600781526020016613d9999cdd5a5d60ca1b815250612e31565b604051806040016040528060018152602001606f60f81b8152509550505050505b5092915050565b600a546001600160a01b03163314612f135760405162461bcd60e51b8152600401610dc49061579f565b600d54610100900460ff1615612f565760405162461bcd60e51b81526020600482015260086024820152671d5c1b1bd859195960c21b6044820152606401610dc4565b60005b82518160ff161015612fdd57818160ff1681518110612f7a57612f7a6156a7565b60200260200101516105406000858460ff1681518110612f9c57612f9c6156a7565b6020026020010151815260200190815260200160002060006101000a81548160ff021916908360ff1602179055508080612fd5906158aa565b915050612f59565b50600d805461ff0019166101001790556040517fb41671ac5b828fa53649b0a11eed2c724fdd89d0e768c0ed3873dcffa25dea1690600090a15050565b600a546001600160a01b031633146130445760405162461bcd60e51b8152600401610dc49061579f565b600b54156130645760405162461bcd60e51b8152600401610dc490615c37565b600d5460ff166130865760405162461bcd60e51b8152600401610dc490615681565b61308f816144d0565b5060006130a883836130a2600a436155f2565b406145be565b604080518281523360208201529192507f7efa1de94fe9a97d0a9b97e14bf9ad9c1e6d44837f53c3f742199c0f02c9f50d910160405180910390a1505050565b60007809392ee8e921d5d073aff322e62439fcf32d7f344649470f8f198212156131285760405163e608e18b60e01b815260048101839052602401610dc4565b7809392ee8e921d5d073aff322e62439fcf32d7f344649470f90821315613165576040516371f72a3160e01b815260048101839052602401610dc4565b50670de0b6b3a76400000290565b6000600160ff1b83148061318a5750600160ff1b82145b156131a85760405163b3c754a360e01b815260040160405180910390fd5b600080600085126131b957846131be565b846000035b9150600084126131ce57836131d3565b836000035b905060006131ea83670de0b6b3a76400008461328e565b90506001600160ff1b0381111561321757604051637cb4bef560e01b815260048101829052602401610dc4565b6000198087139086138082186001146132305782613239565b61323983615609565b98975050505050505050565b60008260000361326d57811561325c576000613266565b670de0b6b3a76400005b9050610c38565b61328761328261327c856146cb565b84613c55565b6147b0565b9392505050565b60008080600019858709858702925082811083820303915050806000036132c8578382816132be576132be61596a565b0492505050613287565b8381106132f257604051631dcf306360e21b81526004810182905260248101859052604401610dc4565b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000600160801b821061337a57608091821c916133779082615952565b90505b68010000000000000000821061339d57604091821c9161339a9082615952565b90505b64010000000082106133bc57602091821c916133b99082615952565b90505b6201000082106133d957601091821c916133d69082615952565b90505b61010082106133f557600891821c916133f29082615952565b90505b6010821061341057600491821c9161340d9082615952565b90505b6004821061342b57600291821c916134289082615952565b90505b6002821061343e57610c38600182615952565b919050565b60008080600019848609848602925082811083820303915050670de0b6b3a764000081106134875760405163698d9a0160e11b815260048101829052602401610dc4565b600080670de0b6b3a764000086880991506706f05b59d3b1ffff82119050826000036134c55780670de0b6b3a7640000850401945050505050610c38565b620400008285030493909111909103600160ee1b02919091177faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106690201905092915050565b600160bf1b67800000000000000082161561352d5768016a09e667f3bcc9090260401c5b67400000000000000082161561354c576801306fe0a31b7152df0260401c5b67200000000000000082161561356b576801172b83c7d517adce0260401c5b67100000000000000082161561358a5768010b5586cf9890f62a0260401c5b6708000000000000008216156135a9576801059b0d31585743ae0260401c5b6704000000000000008216156135c857680102c9a3e778060ee70260401c5b6702000000000000008216156135e75768010163da9fb33356d80260401c5b67010000000000000082161561360657680100b1afa5abcbed610260401c5b66800000000000008216156136245768010058c86da1c09ea20260401c5b6640000000000000821615613642576801002c605e2e8cec500260401c5b662000000000000082161561366057680100162f3904051fa10260401c5b661000000000000082161561367e576801000b175effdc76ba0260401c5b660800000000000082161561369c57680100058ba01fb9f96d0260401c5b66040000000000008216156136ba5768010002c5cc37da94920260401c5b66020000000000008216156136d8576801000162e525ee05470260401c5b66010000000000008216156136f65768010000b17255775c040260401c5b65800000000000821615613713576801000058b91b5bc9ae0260401c5b6540000000000082161561373057680100002c5c89d5ec6d0260401c5b6520000000000082161561374d5768010000162e43f4f8310260401c5b6510000000000082161561376a57680100000b1721bcfc9a0260401c5b650800000000008216156137875768010000058b90cf1e6e0260401c5b650400000000008216156137a4576801000002c5c863b73f0260401c5b650200000000008216156137c157680100000162e430e5a20260401c5b650100000000008216156137de576801000000b1721835510260401c5b6480000000008216156137fa57680100000058b90c0b490260401c5b6440000000008216156138165768010000002c5c8601cc0260401c5b642000000000821615613832576801000000162e42fff00260401c5b64100000000082161561384e5768010000000b17217fbb0260401c5b64080000000082161561386a576801000000058b90bfce0260401c5b64040000000082161561388657680100000002c5c85fe30260401c5b6402000000008216156138a25768010000000162e42ff10260401c5b6401000000008216156138be57680100000000b17217f80260401c5b63800000008216156138d95768010000000058b90bfc0260401c5b63400000008216156138f4576801000000002c5c85fe0260401c5b632000000082161561390f57680100000000162e42ff0260401c5b631000000082161561392a576801000000000b17217f0260401c5b630800000082161561394557680100000000058b90c00260401c5b63040000008216156139605768010000000002c5c8600260401c5b630200000082161561397b576801000000000162e4300260401c5b63010000008216156139965768010000000000b172180260401c5b628000008216156139b0576801000000000058b90c0260401c5b624000008216156139ca57680100000000002c5c860260401c5b622000008216156139e45768010000000000162e430260401c5b621000008216156139fe57680100000000000b17210260401c5b62080000821615613a185768010000000000058b910260401c5b62040000821615613a32576801000000000002c5c80260401c5b62020000821615613a4c57680100000000000162e40260401c5b62010000821615613a66576801000000000000b1720260401c5b618000821615613a7f57680100000000000058b90260401c5b614000821615613a985768010000000000002c5d0260401c5b612000821615613ab1576801000000000000162e0260401c5b611000821615613aca5768010000000000000b170260401c5b610800821615613ae3576801000000000000058c0260401c5b610400821615613afc57680100000000000002c60260401c5b610200821615613b1557680100000000000001630260401c5b610100821615613b2e57680100000000000000b10260401c5b6080821615613b4657680100000000000000590260401c5b6040821615613b5e576801000000000000002c0260401c5b6020821615613b7657680100000000000000160260401c5b6010821615613b8e576801000000000000000b0260401c5b6008821615613ba657680100000000000000060260401c5b6004821615613bbe57680100000000000000030260401c5b6002821615613bd657680100000000000000010260401c5b6001821615613bee57680100000000000000010260401c5b670de0b6b3a76400000260409190911c60bf031c90565b60006001600160e01b031982166380ac58cd60e01b1480613c3657506001600160e01b03198216635b5e139f60e01b145b80610c3857506301ffc9a760e01b6001600160e01b0319831614610c38565b6000600160ff1b831480613c6c5750600160ff1b82145b15613c8a57604051630d01a11b60e21b815260040160405180910390fd5b60008060008512613c9b5784613ca0565b846000035b915060008412613cb05783613cb5565b836000035b90506000613cc38383613443565b90506001600160ff1b03811115613cf05760405163bf79e8d960e01b815260048101829052602401610dc4565b600019808713908613808218600114613d095782613239565b505060000395945050505050565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190613d4c8261194f565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b0316613dfe5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610dc4565b6000613e098361194f565b9050806001600160a01b0316846001600160a01b03161480613e445750836001600160a01b0316613e3984610d4f565b6001600160a01b0316145b80611f4957506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff16611f49565b826001600160a01b0316613e8b8261194f565b6001600160a01b031614613ef35760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610dc4565b6001600160a01b038216613f555760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610dc4565b613f60838383614848565b613f6b600082613d17565b6001600160a01b0383166000908152600360205260408120805460019290613f949084906155f2565b90915550506001600160a01b0382166000908152600360205260408120805460019290613fc2908490615952565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61194b828260405180602001604052806000815250614900565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60608160008190036140ba5750506040805180820190915260018152600360fc1b6020820152919050565b8060005b81156140e457806140ce81615a6c565b91506140dd9050600a83615a58565b91506140be565b60008167ffffffffffffffff8111156140ff576140ff615115565b6040519080825280601f01601f191660200182016040528015614129576020820181803683370190505b5090505b83156141945761413e6001836155f2565b915061414b600a85615980565b614156906030615952565b60f81b81838151811061416b5761416b6156a7565b60200101906001600160f81b031916908160001a90535061418d600a85615a58565b935061412d565b95945050505050565b600b54156141bd5760405162461bcd60e51b8152600401610dc490615c37565b6141c681614492565b600b546040805184815260208101849052908101919091527fad7e9c69b0cb3a7ac544ede8f700bb897c8ee8ea84069062d1a7819e364f439f90606001612792565b600061054754431161421c57506105495490565b6000614235610547544361423091906155f2565b6130e8565b9050600061427461426f7f00000000000000000000000000000000000000000000000aa00be18c2890000061426985615609565b90613173565b614933565b61054954909150610cb69082613c55565b61428e816130e8565b614296610c3e565b6142a09190615911565b610548556142ad826117c1565b610549556142b96149a3565b6105475550504361054655565b6142d1848484613e78565b6142dd84848484614a51565b6117a05760405162461bcd60e51b8152600401610dc490615c5d565b606083838360405160200161431093929190615caf565b60405160208183030381529060405290509392505050565b8051606090600081900361434c575050604080516020810190915260008152919050565b6000600361435b836002615952565b6143659190615a58565b614370906004615a39565b9050600061437f826020615952565b67ffffffffffffffff81111561439757614397615115565b6040519080825280601f01601f1916602001820160405280156143c1576020820181803683370190505b5090506000604051806060016040528060408152602001615eda604091399050600181016020830160005b8681101561444d576003818a01810151603f601282901c8116860151600c83901c8216870151600684901c831688015192909316870151600891821b60ff94851601821b92841692909201901b91160160e01b8352600490920191016143ec565b506003860660018114614467576002811461447857614484565b613d3d60f01b600119830152614484565b603d60f81b6000198301525b505050918152949350505050565b61449f600161052e6155f2565b6144a99082615980565b600b8190556000036144bb576001600b555b61052d600b5411156128825761052d600b5550565b61054154604051633950935160e01b81526001600160a01b039182166004820152602481018390526000917f000000000000000000000000892a6f9df0147e5f079b0993f486f9aca3c8788116906339509351906044016020604051808303816000875af1158015614546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061456a9190615dc7565b6145b65760405162461bcd60e51b815260206004820152601c60248201527f6661696c656420746f20696e63726561736520616c6c6f77616e6365000000006044820152606401610dc4565b506001919050565b6105415460405163264eb1cf60e01b81526004810185905260248101839052604481018490526000916001600160a01b03169063264eb1cf90606401600060405180830381600087803b15801561461457600080fd5b505af1158015614628573d6000803e3d6000fd5b5050506000858152610542602081815260408084205481518084018b905280830189905230606082015260808082018390528351808303909101815260a09091019092528151918301919091209389905291905290915061468a906001614b52565b600086815261054260205260409020556141948582604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b60008082136146f05760405163309fa7dd60e11b815260048101839052602401610dc4565b6000670de0b6b3a7640000831261470957506001614723565b6000199050826ec097ce7bc90715b34b9f10000000000492505b6000614738670de0b6b3a7640000850561335a565b670de0b6b3a764000081029350905083811d670de0b6b3a763ffff19810161476257505002919050565b6706f05b59d3b200005b60008113156147a757670de0b6b3a7640000828002059150671bc16d674ec80000821261479f579384019360019190911d905b60011d61476c565b50505002919050565b6000808212156148045768033dd1780914b97114198212156147d457506000919050565b6147e0826000036147b0565b6ec097ce7bc90715b34b9f1000000000816147fd576147fd61596a565b0592915050565b680a688906bd8b00000082126148305760405163e69458f960e01b815260048101839052602401610dc4565b670de0b6b3a7640000604083901b0461328781613509565b6001600160a01b0383166148a35761489e81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6148c6565b816001600160a01b0316836001600160a01b0316146148c6576148c68382614bb1565b6001600160a01b0382166148dd57610ef981614c4e565b826001600160a01b0316826001600160a01b031614610ef957610ef98282614cfd565b61490a8383614d41565b6149176000848484614a51565b610ef95760405162461bcd60e51b8152600401610dc490615c5d565b600068023f2fa8f6da5b9d311982121561494f57506000919050565b680736ea4425c11ac631821261497b576040516399bb754160e01b815260048101839052602401610dc4565b6714057b7ef767814f8202613287670de0b6b3a76400006706f05b59d3b200008301056147b0565b6000806149dc7f0000000000000000000000000000000000000000000000011f4bc49a7eaf5cbe6105485461317390919063ffffffff16565b90506149e860016130e8565b811315614a49576000614a3d614a2f614a2a614a03856146cb565b7f00000000000000000000000000000000000000000000000aa00be18c2890000090613c55565b614e8f565b670de0b6b3a7640000900590565b9050610cb68143615952565b4391505b5090565b60006001600160a01b0384163b15614b4757604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614a95903390899088908890600401615de4565b6020604051808303816000875af1925050508015614ad0575060408051601f3d908101601f19168201909252614acd91810190615e21565b60015b614b2d573d808015614afe576040519150601f19603f3d011682016040523d82523d6000602084013e614b03565b606091505b508051600003614b255760405162461bcd60e51b8152600401610dc490615c5d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611f49565b506001949350505050565b600080614b5f8385615952565b9050838110156132875760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610dc4565b60006001614bbe846119c6565b614bc891906155f2565b600083815260076020526040902054909150808214614c1b576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090614c60906001906155f2565b60008381526009602052604081205460088054939450909284908110614c8857614c886156a7565b906000526020600020015490508060088381548110614ca957614ca96156a7565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480614ce157614ce1615e3e565b6001900381819060005260206000200160009055905550505050565b6000614d08836119c6565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6001600160a01b038216614d975760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610dc4565b6000818152600260205260409020546001600160a01b031615614dfc5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610dc4565b614e0860008383614848565b6001600160a01b0382166000908152600360205260408120805460019290614e31908490615952565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000670afdc366fbc00000600160ff1b03821315614ec357604051635399a28560e11b815260048101839052602401610dc4565b670de0b6b3a764000082076000819003614edf57829150611321565b808303915060008313156113215750670de0b6b3a764000001919050565b60405180608001604052806004905b6060815260200190600190039081614f0c5790505090565b828054614f3090615625565b90600052602060002090601f016020900481019282614f525760008555614f98565b82601f10614f6b57805160ff1916838001178555614f98565b82800160010185558215614f98579182015b82811115614f98578251825591602001919060010190614f7d565b50614a4d9291505b80821115614a4d5760008155600101614fa0565b6001600160e01b03198116811461288257600080fd5b600060208284031215614fdc57600080fd5b813561328781614fb4565b60005b83811015615002578181015183820152602001614fea565b838111156117a05750506000910152565b6000815180845261502b816020860160208601614fe7565b601f01601f19169290920160200192915050565b6020815260006132876020830184615013565b60006020828403121561506457600080fd5b5035919050565b80356001600160a01b038116811461343e57600080fd5b6000806040838503121561509557600080fd5b61509e8361506b565b946020939093013593505050565b803561ffff8116811461343e57600080fd5b6000602082840312156150d057600080fd5b613287826150ac565b6000806000606084860312156150ee57600080fd5b6150f78461506b565b92506151056020850161506b565b9150604084013590509250925092565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561514e5761514e615115565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561517d5761517d615115565b604052919050565b600067ffffffffffffffff82111561519f5761519f615115565b5060051b60200190565b60ff8116811461288257600080fd5b803561343e816151a9565b600067ffffffffffffffff8211156151dd576151dd615115565b50601f01601f191660200190565b60006151fe6151f9846151c3565b615154565b905082815283838301111561521257600080fd5b828260208301376000602084830101529392505050565b600082601f83011261523a57600080fd5b613287838335602085016151eb565b60008060006060848603121561525e57600080fd5b833567ffffffffffffffff8082111561527657600080fd5b8186019150601f878184011261528b57600080fd5b8235602061529b6151f983615185565b82815260069290921b8501810191818101908b8411156152ba57600080fd5b958201955b83871015615328578b858801126152d65760008081fd5b6152de61512b565b80604089018e8111156152f15760008081fd5b895b81811015615313578035615306816151a9565b84529286019286016152f3565b505083525060409690960195908201906152bf565b985061533790508982016151b8565b9650505050604086013591508082111561535057600080fd5b5061535d86828701615229565b9150509250925092565b60006020828403121561537957600080fd5b6132878261506b565b6000806040838503121561539557600080fd5b50508035926020909101359150565b801515811461288257600080fd5b600080604083850312156153c557600080fd5b6153ce8361506b565b915060208301356153de816153a4565b809150509250929050565b600080600080608085870312156153ff57600080fd5b6154088561506b565b93506154166020860161506b565b925060408501359150606085013567ffffffffffffffff81111561543957600080fd5b8501601f8101871361544a57600080fd5b615459878235602084016151eb565b91505092959194509250565b6000806040838503121561547857600080fd5b6154818361506b565b915061548f6020840161506b565b90509250929050565b600080604083850312156154ab57600080fd5b6153ce836150ac565b600082601f8301126154c557600080fd5b813560206154d56151f983615185565b82815260059290921b840181019181810190868411156154f457600080fd5b8286015b8481101561551857803561550b816151a9565b83529183019183016154f8565b509695505050505050565b6000806040838503121561553657600080fd5b823567ffffffffffffffff8082111561554e57600080fd5b818501915085601f83011261556257600080fd5b813560206155726151f983615185565b82815260059290921b8401810191818101908984111561559157600080fd5b948201945b838610156155af57853582529482019490820190615596565b965050860135925050808211156155c557600080fd5b506155d2858286016154b4565b9150509250929050565b634e487b7160e01b600052601160045260246000fd5b600082821015615604576156046155dc565b500390565b6000600160ff1b820161561e5761561e6155dc565b5060000390565b600181811c9082168061563957607f821691505b60208210810361132157634e487b7160e01b600052602260045260246000fd5b6020808252600e908201526d1a5b9d985b1a59081a185b99125960921b604082015260600190565b6020808252600c908201526b1b9bdd081c995d99585b195960a21b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156156cf57600080fd5b8151613287816151a9565b6000602082840312156156ec57600080fd5b815167ffffffffffffffff81111561570357600080fd5b8201601f8101841361571457600080fd5b80516157226151f9826151c3565b81815285602083850101111561573757600080fd5b614194826020830160208601614fe7565b6000855161575a818460208a01614fe7565b85519083019061576e818360208a01614fe7565b8551910190615781818360208901614fe7565b8451910190615794818360208801614fe7565b019695505050505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b81516000908290602080860184805b8481101561587757825186835b600281101561586157825160ff1682529186019190860190600101615841565b5050506040959095019491830191600101615834565b5093979650505050505050565b600061ffff8083168185168083038211156158a1576158a16155dc565b01949350505050565b600060ff821660ff81036158c0576158c06155dc565b60010192915050565b600061ffff838116908316818110156158e4576158e46155dc565b039392505050565b600060ff821660ff84168060ff03821115615909576159096155dc565b019392505050565b600080821280156001600160ff1b0384900385131615615933576159336155dc565b600160ff1b839003841281161561594c5761594c6155dc565b50500190565b60008219821115615965576159656155dc565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261598f5761598f61596a565b500690565b6000895160206159a78285838f01614fe7565b8a51918401916159ba8184848f01614fe7565b8a519201916159cc8184848e01614fe7565b89519201916159de8184848d01614fe7565b88519201916159f08184848c01614fe7565b8751920191615a028184848b01614fe7565b8651920191615a148184848a01614fe7565b8551920191615a268184848901614fe7565b919091019b9a5050505050505050505050565b6000816000190483118215151615615a5357615a536155dc565b500290565b600082615a6757615a6761596a565b500490565b600060018201615a7e57615a7e6155dc565b5060010190565b60008451615a97818460208901614fe7565b845190830190615aab818360208901614fe7565b8451910190615abe818360208801614fe7565b0195945050505050565b693d913730b6b2911d101160b11b81528351600090615aee81600a850160208901614fe7565b7f222c20226465736372697074696f6e223a2022686f6c64656d6865726f65732e600a918401918201526418dbdb488b60da1b602a8201528451615b3981602f840160208901614fe7565b7f22696d616765223a2022646174613a696d6167652f7376672b786d6c3b626173602f929091019182015263194d8d0b60e21b604f8201528351615b84816053840160208801614fe7565b61227d60f01b6053929091019182015260550195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251615bd881601d850160208701614fe7565b91909101601d0192915050565b6372616e6b60e01b815260008251615c04816004850160208701614fe7565b9190910160040192915050565b60008351615c23818460208801614fe7565b8351908301906158a1818360208801614fe7565b6020808252600c908201526b616c726561647920646f6e6560a01b604082015260600190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b7f2261747472696275746573223a205b7b202274726169745f74797065223a202281527129b430b832911610113b30b63ab2911d101160711b602082015260008451615d02816032850160208901614fe7565b62089f4b60ea1b60329184019182018190527f7b202274726169745f74797065223a202248616e64222c202276616c7565223a603583015261101160f11b605583018190528651615d5a816057860160208b01614fe7565b60579301928301919091527f7b202274726169745f74797065223a202252616e6b222c202276616c7565223a605a830152607a8201528351615da381607c840160208801614fe7565b615dbc607c8284010163089f574b60e21b815260040190565b979650505050505050565b600060208284031215615dd957600080fd5b8151613287816153a4565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e1790830184615013565b9695505050505050565b600060208284031215615e3357600080fd5b815161328781614fb4565b634e487b7160e01b600052603160045260246000fdfe3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f7376672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f313939392f786c696e6b222076696577426f783d2230203020313438203632222077696474683d2235696e22206865696768743d22322e313437696e223e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212202368e0dc7711ed437a6113708eefa64ae68ccb1c529d3cb7b5d18ec918aec2ad64736f6c634300080d0033

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

000000000000000000000000ceb679de692660dd701837c25a4181492050ed8f000000000000000000000000892a6f9df0147e5f079b0993f486f9aca3c87881000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e0000000000000000000000000000000000000000000000000000000000df1e5c00000000000000000000000000000000000000000000000000000000626406600000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000c40000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c4000000000000000000000000000000000000000000000000016345785d8a0000

-----Decoded View---------------
Arg [0] : _vorCoordinator (address): 0xCeB679DE692660dD701837c25a4181492050ED8F
Arg [1] : _xfund (address): 0x892A6f9dF0147e5f079b0993F486F9acA3c87881
Arg [2] : _playingCards (address): 0xC3a3D9f2263A82b740B921FBB386eC5820FDDf9e
Arg [3] : _saleStartBlockNum (uint256): 14622300
Arg [4] : _revealTimestamp (uint256): 1650722400
Arg [5] : _maxNfts (uint256): 9
Arg [6] : _targetBlocksPerSale (int256): 14
Arg [7] : _saleHalflife (int256): 196
Arg [8] : _priceSpeed (int256): 1
Arg [9] : _priceSpeedDenominator (int256): 4
Arg [10] : _priceHalflife (int256): 196
Arg [11] : _startingPrice (int256): 100000000000000000

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 000000000000000000000000ceb679de692660dd701837c25a4181492050ed8f
Arg [1] : 000000000000000000000000892a6f9df0147e5f079b0993f486f9aca3c87881
Arg [2] : 000000000000000000000000c3a3d9f2263a82b740b921fbb386ec5820fddf9e
Arg [3] : 0000000000000000000000000000000000000000000000000000000000df1e5c
Arg [4] : 0000000000000000000000000000000000000000000000000000000062640660
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000009
Arg [6] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [7] : 00000000000000000000000000000000000000000000000000000000000000c4
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [10] : 00000000000000000000000000000000000000000000000000000000000000c4
Arg [11] : 000000000000000000000000000000000000000000000000016345785d8a0000


Deployed Bytecode Sourcemap

137287:15212:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;112964:224;;;;;;;;;;-1:-1:-1;112964:224:0;;;;;:::i;:::-;;:::i;:::-;;;565:14:1;;558:22;540:41;;528:2;513:18;112964:224:0;;;;;;;;137805:32;;;;;;;;;;;;;;;;;;;738:25:1;;;726:2;711:18;137805:32:0;592:177:1;142331:374:0;;;;;;;;;;;;;:::i;100092:100::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;101651:221::-;;;;;;;;;;-1:-1:-1;101651:221:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;2054:32:1;;;2036:51;;2024:2;2009:18;101651:221:0;1890:203:1;101174:411:0;;;;;;;;;;-1:-1:-1;101174:411:0;;;;;:::i;:::-;;:::i;:::-;;130721:820;;;;;;;;;;-1:-1:-1;130721:820:0;;;;;:::i;:::-;;:::i;122779:26::-;;;;;;;;;;-1:-1:-1;122779:26:0;;;;;;;;;;;141918:118;;;;;;;;;;-1:-1:-1;141918:118:0;;;;;:::i;:::-;;:::i;113604:113::-;;;;;;;;;;-1:-1:-1;113692:10:0;:17;113604:113;;122612:31;;;;;;;;;;;;;;;;102541:339;;;;;;;;;;-1:-1:-1;102541:339:0;;;;;:::i;:::-;;:::i;113272:256::-;;;;;;;;;;-1:-1:-1;113272:256:0;;;;;:::i;:::-;;:::i;123270:36::-;;;;;;;;;;-1:-1:-1;123270:36:0;;;;;;;;;;;;;;3393:4:1;3381:17;;;3363:36;;3351:2;3336:18;123270:36:0;3221:184:1;126186:971:0;;;;;;;;;;-1:-1:-1;126186:971:0;;;;;:::i;:::-;;:::i;102951:185::-;;;;;;;;;;-1:-1:-1;102951:185:0;;;;;:::i;:::-;;:::i;123237:26::-;;;;;;;;;;-1:-1:-1;123237:26:0;;;;;;;;;;;7367:6:1;7355:19;;;7337:38;;7325:2;7310:18;123237:26:0;7193:188:1;145091:456:0;;;;;;;;;;-1:-1:-1;145091:456:0;;;;;:::i;:::-;;:::i;138161:39::-;;;;;;;;;;;;;;;;122298:108;;;;;;;;;;-1:-1:-1;122298:108:0;122340:66;122298:108;;138376:33;;;;;;;;;;;;;;;113794:233;;;;;;;;;;-1:-1:-1;113794:233:0;;;;;:::i;:::-;;:::i;123541:43::-;;;;;;;;;;-1:-1:-1;123541:43:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;148555:222;;;;;;:::i;:::-;;:::i;123650:43::-;;;;;;;;;;;;;;;99786:239;;;;;;;;;;-1:-1:-1;99786:239:0;;;;;:::i;:::-;;:::i;122876:26::-;;;;;;;;;;;;;;;;99516:208;;;;;;;;;;-1:-1:-1;99516:208:0;;;;;:::i;:::-;;:::i;60115:94::-;;;;;;;;;;;;;:::i;133074:271::-;;;;;;;;;;-1:-1:-1;133074:271:0;;;;;:::i;:::-;;:::i;132095:641::-;;;;;;;;;;-1:-1:-1;132095:641:0;;;;;:::i;:::-;;:::i;59464:87::-;;;;;;;;;;-1:-1:-1;59537:6:0;;-1:-1:-1;;;;;59537:6:0;59464:87;;123093:23;;;;;;;;;;-1:-1:-1;123093:23:0;;;;;:::i;:::-;;:::i;:::-;;;;8554:4:1;8542:17;;;8524:36;;8596:17;;;;8591:2;8576:18;;8569:45;8497:18;123093:23:0;8358:262:1;79879:220:0;;;;;;;;;;-1:-1:-1;79879:220:0;;;;;:::i;:::-;;:::i;100261:104::-;;;;;;;;;;;;;:::i;138492:36::-;;;;;;;;;;;;;;;138020:37;;;;;;;;;;;;;;;;101944:295;;;;;;;;;;-1:-1:-1;101944:295:0;;;;;:::i;:::-;;:::i;137450:36::-;;;;;;;;;;;;;;;;144314:424;;;;;;;;;;-1:-1:-1;144314:424:0;;;;;:::i;:::-;;:::i;122685:20::-;;;;;;;;;;-1:-1:-1;122685:20:0;;;;;;;;122159:45;;;;;;;;;;;;122200:4;122159:45;;147017:1084;;;;;;:::i;:::-;;:::i;103207:328::-;;;;;;;;;;-1:-1:-1;103207:328:0;;;;;:::i;:::-;;:::i;129217:354::-;;;;;;;;;;-1:-1:-1;129217:354:0;;;;;:::i;:::-;;:::i;138611:34::-;;;;;;;;;;;;;;;143761:162;;;;;;;;;;;;;:::i;133895:1272::-;;;;;;;;;;-1:-1:-1;133895:1272:0;;;;;:::i;:::-;;:::i;129785:177::-;;;;;;;;;;-1:-1:-1;129785:177:0;;;;;:::i;:::-;;:::i;122504:28::-;;;;;;;;;;;;;;;;137585:44;;;;;;;;;;;;;;;;130191:284;;;;;;;;;;-1:-1:-1;130191:284:0;;;;;:::i;:::-;;:::i;149764:457::-;;;;;;;;;;;;;:::i;137541:35::-;;;;;;;;;;;;;;;;137901;;;;;;;;;;;;;;;;123000:29;;;;;;;;;;;;;:::i;138718:37::-;;;;;;;;;;;;;;;125437:112;;;;;;;;;;;;;:::i;102310:164::-;;;;;;;;;;-1:-1:-1;102310:164:0;;;;;:::i;:::-;-1:-1:-1;;;;;102431:25:0;;;102407:4;102431:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;102310:164;128486:389;;;;;;;;;;-1:-1:-1;128486:389:0;;;;;:::i;:::-;;:::i;60364:192::-;;;;;;;;;;-1:-1:-1;60364:192:0;;;;;:::i;:::-;;:::i;127514:681::-;;;;;;;;;;-1:-1:-1;127514:681:0;;;;;:::i;:::-;;:::i;125012:334::-;;;;;;;;;;-1:-1:-1;125012:334:0;;;;;:::i;:::-;;:::i;149165:304::-;;;;;;;;;;-1:-1:-1;149165:304:0;;;;;:::i;:::-;;:::i;112964:224::-;113066:4;-1:-1:-1;;;;;;113090:50:0;;-1:-1:-1;;;113090:50:0;;:90;;;113144:36;113168:11;113144:23;:36::i;:::-;113083:97;112964:224;-1:-1:-1;;112964:224:0:o;142331:374::-;142377:13;142403:20;142448:17;;142433:12;:32;;;;:::i;:::-;142403:63;;142493:23;:13;:21;:23::i;:::-;142477:39;-1:-1:-1;142527:19:0;142549:87;142594:31;142477:39;142612:12;142594:17;:31::i;:::-;142593:32;;;:::i;:::-;142549:25;142572:1;142549:22;:25::i;:::-;:29;;:87::i;:::-;142656:23;;142527:109;;-1:-1:-1;142656:41:0;;142527:109;142656:27;:41::i;:::-;142647:50;;142392:313;;142331:374;:::o;100092:100::-;100146:13;100179:5;100172:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100092:100;:::o;101651:221::-;101727:7;105134:16;;;:7;:16;;;;;;-1:-1:-1;;;;;105134:16:0;101747:73;;;;-1:-1:-1;;;101747:73:0;;13453:2:1;101747:73:0;;;13435:21:1;13492:2;13472:18;;;13465:30;13531:34;13511:18;;;13504:62;-1:-1:-1;;;13582:18:1;;;13575:42;13634:19;;101747:73:0;;;;;;;;;-1:-1:-1;101840:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;101840:24:0;;101651:221::o;101174:411::-;101255:13;101271:23;101286:7;101271:14;:23::i;:::-;101255:39;;101319:5;-1:-1:-1;;;;;101313:11:0;:2;-1:-1:-1;;;;;101313:11:0;;101305:57;;;;-1:-1:-1;;;101305:57:0;;13866:2:1;101305:57:0;;;13848:21:1;13905:2;13885:18;;;13878:30;13944:34;13924:18;;;13917:62;-1:-1:-1;;;13995:18:1;;;13988:31;14036:19;;101305:57:0;13664:397:1;101305:57:0;58418:10;-1:-1:-1;;;;;101397:21:0;;;;:62;;-1:-1:-1;101422:37:0;101439:5;58418:10;102310:164;:::i;101422:37::-;101375:168;;;;-1:-1:-1;;;101375:168:0;;14268:2:1;101375:168:0;;;14250:21:1;14307:2;14287:18;;;14280:30;14346:34;14326:18;;;14319:62;14417:26;14397:18;;;14390:54;14461:19;;101375:168:0;14066:420:1;101375:168:0;101556:21;101565:2;101569:7;101556:8;:21::i;:::-;101244:341;101174:411;;:::o;130721:820::-;130799:13;130777:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;130826:11:::1;130839::::0;130854:24:::1;130871:6;130854:16;:24::i;:::-;130825:53;;;;130891:22;;:::i;:::-;130924:156;;;;;;;;;;;;;;;;;::::0;;131127:39:::1;::::0;-1:-1:-1;;;131127:39:0;;3393:4:1;3381:17;;131127:39:0::1;::::0;::::1;3363:36:1::0;-1:-1:-1;;;;;131102:12:0::1;:24;::::0;::::1;::::0;;;131127:32:::1;::::0;3336:18:1;;131127:39:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131168:37;::::0;-1:-1:-1;;;131168:37:0;;3393:4:1;3381:17;;131168:37:0::1;::::0;::::1;3363:36:1::0;131168:12:0::1;-1:-1:-1::0;;;;;131168:30:0::1;::::0;::::1;::::0;3336:18:1;;131168:37:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131102:114;::::0;-1:-1:-1;;;;;;131102:114:0::1;::::0;;;;;;15865:4:1;15853:17;;;131102:114:0::1;::::0;::::1;15835:36:1::0;15907:17;;15887:18;;;15880:45;131207:1:0::1;15941:18:1::0;;;15934:34;131210:2:0::1;15984:18:1::0;;;15977:34;131214:1:0::1;16027:19:1::0;;;16020:35;15807:19;;131102:114:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;131102:114:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;131091:8;::::0;::::1;:125:::0;131263:39:::1;::::0;-1:-1:-1;;;131263:39:0;;3393:4:1;3381:17;;131263:39:0::1;::::0;::::1;3363:36:1::0;-1:-1:-1;;;;;131238:12:0::1;:24;::::0;::::1;::::0;;;131263:32:::1;::::0;3336:18:1;;131263:39:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131304:37;::::0;-1:-1:-1;;;131304:37:0;;3393:4:1;3381:17;;131304:37:0::1;::::0;::::1;3363:36:1::0;131304:12:0::1;-1:-1:-1::0;;;;;131304:30:0::1;::::0;::::1;::::0;3336:18:1;;131304:37:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131238:117;::::0;-1:-1:-1;;;;;;131238:117:0::1;::::0;;;;;;15865:4:1;15853:17;;;131238:117:0::1;::::0;::::1;15835:36:1::0;15907:17;;15887:18;;;15880:45;131343:2:0::1;15941:18:1::0;;;15934:34;131347:3:0::1;15984:18:1::0;;;15977:34;131352:2:0::1;16027:19:1::0;;;16020:35;15807:19;;131238:117:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;131238:117:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;131227:8:::0;;;::::1;:128:::0;;;131366:19;;;;::::1;::::0;;::::1;::::0;;-1:-1:-1;;;131227:8:0::1;131366:19:::0;;::::1;::::0;;;;:8;;::::1;:19:::0;;;131459:8;;131469;;::::1;::::0;131479;;131442:56;;-1:-1:-1;;131442:56:0::1;::::0;131459:8;;131469;;131366:19;;131442:56:::1;;:::i;:::-;;::::0;;-1:-1:-1;;131442:56:0;;::::1;::::0;;;;;;;-1:-1:-1;;;;;137269:1:0::1;130721:820:::0;;;;:::o;141918:118::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;141998:19:::1;:30:::0;141918:118::o;102541:339::-;102736:41;58418:10;102769:7;102736:18;:41::i;:::-;102728:103;;;;-1:-1:-1;;;102728:103:0;;;;;;;:::i;:::-;102844:28;102854:4;102860:2;102864:7;102844:9;:28::i;113272:256::-;113369:7;113405:23;113422:5;113405:16;:23::i;:::-;113397:5;:31;113389:87;;;;-1:-1:-1;;;113389:87:0;;19061:2:1;113389:87:0;;;19043:21:1;19100:2;19080:18;;;19073:30;19139:34;19119:18;;;19112:62;-1:-1:-1;;;19190:18:1;;;19183:41;19241:19;;113389:87:0;18859:407:1;113389:87:0;-1:-1:-1;;;;;;113494:19:0;;;;;;;;:12;:19;;;;;;;;:26;;;;;;;;;113272:256::o;126186:971::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;126318:16:::1;;126299:15;:35;;126291:55;;;::::0;-1:-1:-1;;;126291:55:0;;19473:2:1;126291:55:0::1;::::0;::::1;19455:21:1::0;19512:1;19492:18;;;19485:29;-1:-1:-1;;;19530:18:1;;;19523:37;19577:18;;126291:55:0::1;19271:330:1::0;126291:55:0::1;126365:12;::::0;126380:4:::1;126365:12;::::0;;::::1;:19;126357:40;;;::::0;-1:-1:-1;;;126357:40:0;;19808:2:1;126357:40:0::1;::::0;::::1;19790:21:1::0;19847:1;19827:18;;;19820:29;-1:-1:-1;;;19865:18:1;;;19858:38;19913:18;;126357:40:0::1;19606:331:1::0;126357:40:0::1;126427:19;::::0;::::1;126416:30:::0;;::::1;126427:19:::0;;;::::1;;126416:30;126408:56;;;::::0;-1:-1:-1;;;126408:56:0;;20144:2:1;126408:56:0::1;::::0;::::1;20126:21:1::0;20183:2;20163:18;;;20156:30;-1:-1:-1;;;20202:18:1;;;20195:43;20255:18;;126408:56:0::1;19942:337:1::0;126408:56:0::1;126475:16;126521:6;126504:24;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;126504:24:0;;::::1;::::0;;;;;;126494:35;;126504:24:::1;126494:35:::0;;::::1;::::0;126549:24:::1;::::0;;;:14:::1;:24:::0;;;;;;126494:35;;-1:-1:-1;126549:24:0::1;;126548:25;126540:51;;;::::0;-1:-1:-1;;;126540:51:0;;21443:2:1;126540:51:0::1;::::0;::::1;21425:21:1::0;21482:2;21462:18;;;21455:30;-1:-1:-1;;;21501:18:1;;;21494:43;21554:18;;126540:51:0::1;21241:337:1::0;126540:51:0::1;126602:24;::::0;;;:14:::1;:24;::::0;;;;:31;;-1:-1:-1;;126602:31:0::1;126629:4;126602:31;::::0;;126644:168:::1;126666:6;:13;126662:1;:17;;;126644:168;;;126723:31;;;;;;;;126728:6;126735:1;126728:9;;;;;;;;;;:::i;:::-;;;;;;;126738:1;126728:12;;;;;;;:::i;:::-;;;;;126723:31;;;;;;126741:6;126748:1;126741:9;;;;;;;;;;:::i;:::-;;;;;;;126751:1;126741:12;;;;;;;:::i;:::-;;;;::::0;126723:31:::1;;::::0;;126707:12:::1;::::0;126701:5:::1;::::0;126707:12:::1;;126701:19;::::0;::::1;;;;;:::i;:::-;:53:::0;;:19;::::1;:53:::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;::::1;;;-1:-1:-1::0;;126701:53:0;;;;::::1;::::0;;;;;;;::::1;::::0;;126784:12:::1;::::0;:16:::1;::::0;:12:::1;;126701:53:::0;126784:16:::1;:::i;:::-;126769:12;:31:::0;;-1:-1:-1;;126769:31:0::1;;::::0;;;::::1;::::0;;;::::1;::::0;;126681:3;::::1;::::0;::::1;:::i;:::-;;;;126644:168;;;-1:-1:-1::0;126863:13:0;;126841:12:::1;::::0;126827:88:::1;::::0;126841:36:::1;::::0;:12:::1;;:36;:::i;:::-;126879:12;::::0;:16:::1;::::0;126894:1:::1;::::0;126879:12:::1;;:16;:::i;:::-;126827:88;::::0;;22447:6:1;22480:15;;;22462:34;;22532:15;;;;22527:2;22512:18;;22505:43;22564:18;;22557:34;;;22639:4;22627:17;;22622:2;22607:18;;22600:45;22424:3;22409:19;126827:88:0::1;;;;;;;126930:12;::::0;::::1;;126946:4;126930:20:::0;126926:224:::1;;126967:8;:15:::0;;-1:-1:-1;;126967:15:0::1;126978:4;126967:15;::::0;;126997:22;;::::1;::::0;:15:::1;::::0;:22:::1;::::0;::::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;127048:12:0::1;127034:11;:26:::0;126926:224:::1;;;127115:19;::::0;:23:::1;::::0;:19;;::::1;;;127137:1;127115:23;:::i;:::-;127093:19;;:45;;;;;;;;;;;;;;;;;;126926:224;126280:877;126186:971:::0;;;:::o;102951:185::-;103089:39;103106:4;103112:2;103116:7;103089:39;;;;;;;;;;;;:16;:39::i;145091:456::-;145183:13;145214:20;145237:38;145265:9;145237:23;;:27;;:38;;;;:::i;:::-;145214:61;;145306:25;145329:1;145306:22;:25::i;:::-;145290:13;:41;145286:254;;;145357:112;145425:29;:13;145443:10;145425:17;:29::i;:::-;145397:25;145420:1;145397:22;:25::i;:::-;:57;;;;:::i;:::-;145357:17;;:21;:112::i;:::-;145348:121;;145286:254;;;-1:-1:-1;145511:17:0;;145091:456;-1:-1:-1;145091:456:0:o;113794:233::-;113869:7;113905:30;113692:10;:17;;113604:113;113905:30;113897:5;:38;113889:95;;;;-1:-1:-1;;;113889:95:0;;23337:2:1;113889:95:0;;;23319:21:1;23376:2;23356:18;;;23349:30;23415:34;23395:18;;;23388:62;-1:-1:-1;;;23466:18:1;;;23459:42;23518:19;;113889:95:0;23135:408:1;113889:95:0;114002:10;114013:5;114002:17;;;;;;;;:::i;:::-;;;;;;;;;113995:24;;113794:233;;;:::o;148555:222::-;148627:13;148643:30;148665:7;148643:21;:30::i;:::-;148627:46;;148705:5;148692:9;:18;;148684:42;;;;-1:-1:-1;;;148684:42:0;;23750:2:1;148684:42:0;;;23732:21:1;23789:2;23769:18;;;23762:30;-1:-1:-1;;;23808:18:1;;;23801:41;23859:18;;148684:42:0;23548:335:1;148684:42:0;148739:30;148749:10;148761:7;148739:9;:30::i;:::-;148616:161;148555:222;:::o;99786:239::-;99858:7;99894:16;;;:7;:16;;;;;;-1:-1:-1;;;;;99894:16:0;;99921:73;;;;-1:-1:-1;;;99921:73:0;;24090:2:1;99921:73:0;;;24072:21:1;24129:2;24109:18;;;24102:30;24168:34;24148:18;;;24141:62;-1:-1:-1;;;24219:18:1;;;24212:39;24268:19;;99921:73:0;23888:405:1;99516:208:0;99588:7;-1:-1:-1;;;;;99616:19:0;;99608:74;;;;-1:-1:-1;;;99608:74:0;;24500:2:1;99608:74:0;;;24482:21:1;24539:2;24519:18;;;24512:30;24578:34;24558:18;;;24551:62;-1:-1:-1;;;24629:18:1;;;24622:40;24679:19;;99608:74:0;24298:406:1;99608:74:0;-1:-1:-1;;;;;;99700:16:0;;;;;:9;:16;;;;;;;99516:208::o;60115:94::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;60180:21:::1;60198:1;60180:9;:21::i;:::-;60115:94::o:0;133074:271::-;133138:6;133193:4;133182:8;:15;133157:55;;;;-1:-1:-1;;;133157:55:0;;24911:2:1;133157:55:0;;;24893:21:1;24950:2;24930:18;;;24923:30;-1:-1:-1;;;24969:18:1;;;24962:40;25019:18;;133157:55:0;24709:334:1;133157:55:0;133247:1;133231:13;;:17;133223:45;;;;-1:-1:-1;;;133223:45:0;;25250:2:1;133223:45:0;;;25232:21:1;25289:2;25269:18;;;25262:30;-1:-1:-1;;;25308:18:1;;;25301:45;25363:18;;133223:45:0;25048:339:1;133223:45:0;122200:4;133305:13;;133294:8;:24;;;;:::i;:::-;133293:43;;;;:::i;132095:641::-;132172:7;132150:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;132193:11:::1;132206::::0;132221:24:::1;132238:6;132221:16;:24::i;:::-;132192:53;;;;132308:16;132317:6;132308:16;;:8;:16::i;:::-;132343:23;132359:6;132343:15;:23::i;:::-;132385:15;132394:5;132385:15;;:8;:15::i;:::-;132428:39;::::0;-1:-1:-1;;;132428:39:0;;3393:4:1;3381:17;;132428:39:0::1;::::0;::::1;3363:36:1::0;132419:49:0::1;::::0;132428:12:::1;-1:-1:-1::0;;;;;132428:32:0::1;::::0;::::1;::::0;3336:18:1;;132428:39:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132419:49;;:8;:49::i;:::-;132496:37;::::0;-1:-1:-1;;;132496:37:0;;3393:4:1;3381:17;;132496:37:0::1;::::0;::::1;3363:36:1::0;132487:47:0::1;::::0;132496:12:::1;-1:-1:-1::0;;;;;132496:30:0::1;::::0;::::1;::::0;3336:18:1;;132496:37:0::1;3221:184:1::0;132487:47:0::1;132553:15;132562:5;132553:15;;:8;:15::i;:::-;132596:39;::::0;-1:-1:-1;;;132596:39:0;;3393:4:1;3381:17;;132596:39:0::1;::::0;::::1;3363:36:1::0;132587:49:0::1;::::0;132596:12:::1;-1:-1:-1::0;;;;;132596:32:0::1;::::0;::::1;::::0;3336:18:1;;132596:39:0::1;3221:184:1::0;132587:49:0::1;132664:37;::::0;-1:-1:-1;;;132664:37:0;;3393:4:1;3381:17;;132664:37:0::1;::::0;::::1;3363:36:1::0;132655:47:0::1;::::0;132664:12:::1;-1:-1:-1::0;;;;;132664:30:0::1;::::0;::::1;::::0;3336:18:1;;132664:37:0::1;3221:184:1::0;132655:47:0::1;132273:444;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;132263:465;;;;;;132256:472;;;;132095:641:::0;;;;:::o;123093:23::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;123093:23:0;;;;;;:::o;79879:220::-;79990:14;;-1:-1:-1;;;;;79990:14:0;79976:10;:28;79968:72;;;;-1:-1:-1;;;79968:72:0;;27622:2:1;79968:72:0;;;27604:21:1;27661:2;27641:18;;;27634:30;27700:33;27680:18;;;27673:61;27751:18;;79968:72:0;27420:355:1;79968:72:0;80051:40;80069:9;80080:10;80051:17;:40::i;100261:104::-;100317:13;100350:7;100343:14;;;;;:::i;101944:295::-;58418:10;-1:-1:-1;;;;;102047:24:0;;;102039:62;;;;-1:-1:-1;;;102039:62:0;;27982:2:1;102039:62:0;;;27964:21:1;28021:2;28001:18;;;27994:30;28060:27;28040:18;;;28033:55;28105:18;;102039:62:0;27780:349:1;102039:62:0;58418:10;102114:32;;;;:18;:32;;;;;;;;-1:-1:-1;;;;;102114:42:0;;;;;;;;;;;;:53;;-1:-1:-1;;102114:53:0;;;;;;;;;;102183:48;;540:41:1;;;102114:42:0;;58418:10;102183:48;;513:18:1;102183:48:0;;;;;;;101944:295;;:::o;144314:424::-;144384:14;144411:12;144434:38;144446:25;144462:8;144446:15;:25::i;144434:38::-;144426:47;;144411:62;;144487:4;144495:1;144487:9;144484:247;;144522:19;;144513:28;;144484:247;;;144574:9;144608:3;144594:10;:4;144601:3;144594:10;:::i;:::-;144593:18;;;;:::i;:::-;144586:26;;:3;:26;:::i;:::-;144574:38;;144652:2;144648:1;:6;144647:17;;144663:1;144647:17;;;144658:2;144647:17;144643:21;;144716:3;144711:1;144689:19;;:23;;;;:::i;:::-;144688:31;;;;:::i;:::-;144679:40;144314:424;-1:-1:-1;;;;144314:424:0:o;147017:1084::-;147094:20;147134:1;147118:13;:17;147117:39;;147155:1;147117:39;;;147139:13;147117:39;147094:62;;147191:20;;147175:12;:36;;147167:60;;;;-1:-1:-1;;;147167:60:0;;28634:2:1;147167:60:0;;;28616:21:1;28673:2;28653:18;;;28646:30;-1:-1:-1;;;28692:18:1;;;28685:41;28743:18;;147167:60:0;28432:335:1;147167:60:0;122200:4;147246:13;113692:10;:17;;113604:113;147246:13;:30;147238:51;;;;-1:-1:-1;;;147238:51:0;;28974:2:1;147238:51:0;;;28956:21:1;29013:1;28993:18;;;28986:29;-1:-1:-1;;;29031:18:1;;;29024:38;29079:18;;147238:51:0;28772:331:1;147238:51:0;147326:16;;147308:15;:34;147300:52;;;;-1:-1:-1;;;147300:52:0;;29310:2:1;147300:52:0;;;29292:21:1;29349:1;29329:18;;;29322:29;-1:-1:-1;;;29367:18:1;;;29360:35;29412:18;;147300:52:0;29108:328:1;147300:52:0;147387:21;;147371:12;:37;;147363:62;;;;-1:-1:-1;;;147363:62:0;;29643:2:1;147363:62:0;;;29625:21:1;29682:2;29662:18;;;29655:30;-1:-1:-1;;;29701:18:1;;;29694:42;29753:18;;147363:62:0;29441:336:1;147363:62:0;147484:21;;147468:12;147444:21;147454:10;147444:9;:21::i;:::-;:36;;;;:::i;:::-;:61;;147436:86;;;;-1:-1:-1;;;147436:86:0;;29984:2:1;147436:86:0;;;29966:21:1;30023:2;30003:18;;;29996:30;-1:-1:-1;;;30042:18:1;;;30035:42;30094:18;;147436:86:0;29782:336:1;147436:86:0;122200:4;147557:12;147541:13;113692:10;:17;;113604:113;147541:13;:28;;;;:::i;:::-;:46;;147533:73;;;;-1:-1:-1;;;147533:73:0;;30325:2:1;147533:73:0;;;30307:21:1;30364:2;30344:18;;;30337:30;-1:-1:-1;;;30383:18:1;;;30376:44;30437:18;;147533:73:0;30123:338:1;147533:73:0;147619:18;147640:14;:12;:14::i;:::-;147619:35;-1:-1:-1;27683:4:0;57761:9;;147665:25;147752:32;147772:12;57761:9;147752:32;:::i;:::-;147732:52;;147818:9;147805;:22;;147797:46;;;;-1:-1:-1;;;147797:46:0;;23750:2:1;147797:46:0;;;23732:21:1;23789:2;23769:18;;;23762:30;-1:-1:-1;;;23808:18:1;;;23801:41;23859:18;;147797:46:0;23548:335:1;147797:46:0;147861:9;147856:150;147880:12;147876:1;:16;147856:150;;;147914:17;147934:13;113692:10;:17;;113604:113;147934:13;147914:33;;147962:32;147972:10;147984:9;147962;:32::i;:::-;-1:-1:-1;147894:3:0;;;;:::i;:::-;;;;147856:150;;;;148048:43;148065:11;148078:12;148048:16;:43::i;:::-;147083:1018;;;;147017:1084;:::o;103207:328::-;103382:41;58418:10;103415:7;103382:18;:41::i;:::-;103374:103;;;;-1:-1:-1;;;103374:103:0;;;;;;;:::i;:::-;103488:39;103502:4;103508:2;103512:7;103521:5;103488:13;:39::i;129217:354::-;129294:13;129272:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;129320:19:::1;129342:26;129355:6;129363:4;129342:12;:26::i;:::-;129320:48;;129380:11;129393::::0;129408:24:::1;129425:6;129408:16;:24::i;:::-;129476:38;::::0;-1:-1:-1;;;129476:38:0;;3393:4:1;3381:17;;129476:38:0::1;::::0;::::1;3363:36:1::0;129379:53:0;;-1:-1:-1;129379:53:0;-1:-1:-1;129476:12:0::1;-1:-1:-1::0;;;;;129476:31:0::1;::::0;::::1;::::0;3336:18:1;;129476:38:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;129476:38:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;129516;::::0;-1:-1:-1;;;129516:38:0;;3393:4:1;3381:17;;129516:38:0::1;::::0;::::1;3363:36:1::0;129516:12:0::1;-1:-1:-1::0;;;;;129516:31:0::1;::::0;::::1;::::0;3336:18:1;;129516:38:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;129516:38:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;129556:5;129459:103;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;129445:118;;;;;129217:354:::0;;;;:::o;143761:162::-;143805:14;143832:18;143853:14;:12;:14::i;:::-;27683:4;57761:9;;;143761:162;-1:-1:-1;;143761:162:0:o;133895:1272::-;133961:13;134212;134228:25;134244:8;134228:15;:25::i;:::-;134212:41;;134266:22;134291:23;134307:6;134291:15;:23::i;:::-;134266:48;;134325:19;134347:27;134360:6;134368:5;134347:12;:27::i;:::-;134325:49;;134385:18;134406:19;134418:6;134406:11;:19::i;:::-;134385:40;;134436:18;134457:29;134466:19;134478:6;134466:11;:19::i;134457:29::-;134436:50;;134499:18;134520:516;134661:8;134767:32;134781:5;134788:4;134794;134767:13;:32::i;:::-;134894:42;134914:20;134927:6;134914:12;:20::i;:::-;134894:13;:42::i;:::-;134601:390;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;134520:13;:516::i;:::-;134499:537;;135047:20;135127:4;135077:55;;;;;;;;:::i;:::-;;;;-1:-1:-1;;135077:55:0;;;;;;;;;;133895:1272;-1:-1:-1;;;;;;;;;133895:1272:0:o;129785:177::-;129862:5;129840:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;129887:9:::1;:67;129932:19;129944:6;129932:11;:19::i;:::-;129907:45;;;;;;;;:::i;:::-;;::::0;;;;::::1;-1:-1:-1::0;;129907:45:0;;;;;;129897:56;;129907:45:::1;129897:56:::0;;::::1;::::0;129887:67;;;;::::1;::::0;;;;;-1:-1:-1;129887:67:0;;::::1;;::::0;129785:177;-1:-1:-1;;;129785:177:0:o;130191:284::-;130272:13;130250:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;130299:11:::1;130312::::0;130327:24:::1;130344:6;130327:16;:24::i;:::-;130393:35;::::0;-1:-1:-1;;;130393:35:0;;3393:4:1;3381:17;;130393:35:0::1;::::0;::::1;3363:36:1::0;130298:53:0;;-1:-1:-1;130298:53:0;-1:-1:-1;130393:12:0::1;-1:-1:-1::0;;;;;130393:28:0::1;::::0;::::1;::::0;3336:18:1;;130393:35:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;130393:35:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;130430;::::0;-1:-1:-1;;;130430:35:0;;3393:4:1;3381:17;;130430:35:0::1;::::0;::::1;3363:36:1::0;130430:12:0::1;-1:-1:-1::0;;;;;130430:28:0::1;::::0;::::1;::::0;3336:18:1;;130430:35:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;130430:35:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;130376:90;;;;;;;;;:::i;:::-;;;;;;;;;;;;;130362:105;;;;130191:284:::0;;;;:::o;149764:457::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;152397:13:::1;::::0;:18;152389:43:::1;;;;-1:-1:-1::0;;;152389:43:0::1;;;;;;;:::i;:::-;152451:8;::::0;::::1;;152443:33;;;;-1:-1:-1::0;;;152443:33:0::1;;;;;;;:::i;:::-;149860:11:::2;::::0;149989:3:::2;149960:26;149860:11:::0;149960:12:::2;:26;:::i;:::-;:32;149956:93;;;150023:14;150036:1;150023:12;:14;:::i;:::-;150009:28;;149956:93;150087:22:::0;::::2;150123:31;150087:22:::0;150123:19:::2;:31::i;:::-;150199:13;::::0;150172:41:::2;::::0;;150191:3:::2;34678:25:1::0;;;34734:2;34719:18;;34712:34;34762:18;;;34755:34;;;;150172:41:0::2;::::0;34666:2:1;34651:18;150172:41:0::2;;;;;;;;149827:394;;149764:457::o:0;123000:29::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;125437:112::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;125490:51:::1;::::0;125498:10:::1;::::0;125519:21:::1;125490:51:::0;::::1;;;::::0;::::1;::::0;;;125519:21;125498:10;125490:51;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;125437:112::o:0;128486:389::-;128568:11;;128546:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;128605:17:::1;128625:5;128631:6;128625:13;;;;;;;;;:::i;:::-;;128733:10:::0;;128700:44:::1;::::0;-1:-1:-1;;;128700:44:0;;128733:10:::1;::::0;;::::1;;;128700:44;::::0;::::1;3363:36:1::0;128625:13:0;;-1:-1:-1;128700:12:0::1;-1:-1:-1::0;;;;;128700:32:0::1;::::0;::::1;::::0;3336:18:1;;128700:44:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;128686:10:::0;;128653:44:::1;::::0;-1:-1:-1;;;128653:44:0;;:91:::1;128686:10:::0;;::::1;128653:44;::::0;::::1;3363:36:1::0;128653:91:0;::::1;::::0;:12:::1;-1:-1:-1::0;;;;;128653:32:0::1;::::0;::::1;::::0;3336:18:1;;128653:44:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:91;;;128649:219;;;128769:10:::0;::::1;::::0;;::::1;::::0;-1:-1:-1;128769:10:0::1;128781::::0;;::::1;;::::0;-1:-1:-1;128761:31:0::1;;128649:219;128833:10:::0;::::1;;::::0;::::1;::::0;::::1;::::0;-1:-1:-1;128845:10:0::1;::::0;-1:-1:-1;137269:1:0::1;128486:389:::0;;;;:::o;60364:192::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;60453:22:0;::::1;60445:73;;;::::0;-1:-1:-1;;;60445:73:0;;35002:2:1;60445:73:0::1;::::0;::::1;34984:21:1::0;35041:2;35021:18;;;35014:30;35080:34;35060:18;;;35053:62;-1:-1:-1;;;35131:18:1;;;35124:36;35177:19;;60445:73:0::1;34800:402:1::0;60445:73:0::1;60529:19;60539:8;60529:9;:19::i;127514:681::-:0;127609:13;127587:6;137191:4;137182:6;:13;;;137159:55;;;;-1:-1:-1;;;137159:55:0;;;;;;;:::i;:::-;137233:8;;;;137225:33;;;;-1:-1:-1;;;137225:33:0;;;;;;;:::i;:::-;127635:12:::1;127650;-1:-1:-1::0;;;;;127650:32:0::1;;127683:5;127689:6;127683:13;;;;;;;;;:::i;:::-;;:19:::0;127650:53:::1;::::0;::::1;::::0;;;-1:-1:-1;;;;;;127650:53:0;;;127683:19:::1;::::0;;::::1;127650:53;::::0;::::1;3363:36:1::0;3336:18;;127650:53:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;127635:68;;127714:12;127729;-1:-1:-1::0;;;;;127729:32:0::1;;127762:5;127768:6;127762:13;;;;;;;;;:::i;:::-;;:19:::0;127729:53:::1;::::0;::::1;::::0;;;-1:-1:-1;;;;;;127729:53:0;;;127762:19:::1;::::0;;::::1;;;127729:53;::::0;::::1;3363:36:1::0;3336:18;;127729:53:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;127714:68;;127795:12;127810;-1:-1:-1::0;;;;;127810:30:0::1;;127841:5;127847:6;127841:13;;;;;;;;;:::i;:::-;;:19:::0;127810:51:::1;::::0;::::1;::::0;;;-1:-1:-1;;;;;;127810:51:0;;;127841:19:::1;::::0;;::::1;127810:51;::::0;::::1;3363:36:1::0;3336:18;;127810:51:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;127795:66;;127872:12;127887;-1:-1:-1::0;;;;;127887:30:0::1;;127918:5;127924:6;127918:13;;;;;;;;;:::i;:::-;;:19:::0;127887:51:::1;::::0;::::1;::::0;;;-1:-1:-1;;;;;;127887:51:0;;;127918:19:::1;::::0;;::::1;;;127887:51;::::0;::::1;3363:36:1::0;3336:18;;127887:51:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;127872:66;;127965:6;127955:16;;:6;:16;;::::0;127951:237:::1;;127995:10;:24;;;;;;;;;;;;;;;-1:-1:-1::0;;;127995:24:0::1;;::::0;::::1;;;;;;;;;;;;;;::::0;::::1;127988:31;;;;;;;;127951:237;128051:6;128041:16;;:6;:16;;::::0;128037:151:::1;;128081:10;:27;;;;;;;;;;;;;;;-1:-1:-1::0;;;128081:27:0::1;;::::0;::::1;;;;;;;;;;;;;;;;-1:-1:-1::0;;;128081:27:0::1;;::::0;128074:34:::1;;;;;;;;128037:151;128148:10;:28;;;;;;;;;;;;;;;-1:-1:-1::0;;;128148:28:0::1;;::::0;::::1;;;;;;;;;;;;;;;;-1:-1:-1::0;;;128148:28:0::1;;::::0;128141:35:::1;;;;;;137269:1;127514:681:::0;;;;;:::o;125012:334::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;125127:14:::1;::::0;::::1;::::0;::::1;;;125126:15;125118:36;;;::::0;-1:-1:-1;;;125118:36:0;;35409:2:1;125118:36:0::1;::::0;::::1;35391:21:1::0;35448:1;35428:18;;;35421:29;-1:-1:-1;;;35466:18:1;;;35459:38;35514:18;;125118:36:0::1;35207:331:1::0;125118:36:0::1;125170:7;125165:108;125187:10;:17;125183:1;:21;;;125165:108;;;125253:5;125259:1;125253:8;;;;;;;;;;:::i;:::-;;;;;;;125226:9;:24;125236:10;125247:1;125236:13;;;;;;;;;;:::i;:::-;;;;;;;125226:24;;;;;;;;;;;;:35;;;;;;;;;;;;;;;;;;125206:3;;;;;:::i;:::-;;;;125165:108;;;-1:-1:-1::0;125283:14:0::1;:21:::0;;-1:-1:-1;;125283:21:0::1;;;::::0;;125320:18:::1;::::0;::::1;::::0;125283:21;;125320:18:::1;125012:334:::0;;:::o;149165:304::-;59537:6;;-1:-1:-1;;;;;59537:6:0;58418:10;59684:23;59676:68;;;;-1:-1:-1;;;59676:68:0;;;;;;;:::i;:::-;152397:13:::1;::::0;:18;152389:43:::1;;;;-1:-1:-1::0;;;152389:43:0::1;;;;;;;:::i;:::-;152451:8;::::0;::::1;;152443:33;;;;-1:-1:-1::0;;;152443:33:0::1;;;;;;;:::i;:::-;149266:38:::2;149299:4;149266:32;:38::i;:::-;-1:-1:-1::0;149315:17:0::2;149335:70;149353:8:::0;149363:4;149387:15:::2;149400:2;149387:12;:15;:::i;:::-;149377:26;149335:17;:70::i;:::-;149421:40;::::0;;35717:25:1;;;149450:10:0::2;35773:2:1::0;35758:18;;35751:60;149315:90:0;;-1:-1:-1;149421:40:0::2;::::0;35690:18:1;149421:40:0::2;;;;;;;149255:214;149165:304:::0;;:::o;37861:377::-;37911:13;-1:-1:-1;;37966:23:0;;37962:106;;;38017:35;;-1:-1:-1;;;38017:35:0;;;;;738:25:1;;;711:18;;38017:35:0;592:177:1;37962:106:0;38090:19;38086:23;;38082:105;;;38137:34;;-1:-1:-1;;;38137:34:0;;;;;738:25:1;;;711:18;;38137:34:0;592:177:1;38082:105:0;-1:-1:-1;27683:4:0;38210:9;;37861:377::o;31343:1137::-;31399:13;-1:-1:-1;;;31429:1:0;:16;:36;;;;-1:-1:-1;;;31449:1:0;:16;31429:36;31425:110;;;31489:34;;-1:-1:-1;;;31489:34:0;;;;;;;;;;;31425:110;31603:10;31624;31679:1;31675;:5;:32;;31705:1;31675:32;;;31692:1;31691:2;;31675:32;31670:37;;31731:1;31727;:5;:32;;31757:1;31727:32;;;31744:1;31743:2;;31727:32;31722:37;;31874:12;31889:38;31904:2;27683:4;31924:2;31889:14;:38::i;:::-;31874:53;;-1:-1:-1;;;;;31942:4:0;:27;31938:100;;;31993:33;;-1:-1:-1;;;31993:33:0;;;;;738:25:1;;;711:18;;31993:33:0;592:177:1;31938:100:0;-1:-1:-1;;32160:17:0;;;;32197;;32429:7;;;32174:1;32429:12;:43;;32467:4;32429:43;;;32444:13;32452:4;32444:13;:::i;:::-;32420:52;31343:1137;-1:-1:-1;;;;;;;;31343:1137:0:o;54139:226::-;54195:13;54225:1;54230;54225:6;54221:137;;54257:6;;:26;;54281:1;54257:26;;;27683:4;54257:26;54248:35;;54221:137;;;54325:21;54330:15;54334:7;54339:1;54334:4;:7::i;:::-;54343:1;54330:3;:15::i;:::-;54325:4;:21::i;:::-;54316:30;54139:226;-1:-1:-1;;;54139:226:0:o;15472:4067::-;15588:14;;;-1:-1:-1;;16084:1:0;16081;16074:20;16124:1;16121;16117:9;16108:18;;16176:5;16172:2;16169:13;16161:5;16157:2;16153:14;16149:34;16140:43;;;16270:5;16279:1;16270:10;16266:143;;16343:11;16335:5;:19;;;;;:::i;:::-;;16326:28;;16384:13;;;;16266:143;16519:11;16510:5;:20;16506:103;;16554:43;;-1:-1:-1;;;16554:43:0;;;;;35996:25:1;;;36037:18;;;36030:34;;;35969:18;;16554:43:0;35822:248:1;16506:103:0;16851:17;16977:11;16974:1;16971;16964:25;18415:1;18396;17534;17519:12;;:16;;17504:32;;17645:25;;;;18396:15;;;18395:21;;18652;;;18648:25;;18637:36;18722:21;;;18718:25;;18707:36;18793:21;;;18789:25;;18778:36;18864:21;;;18860:25;;18849:36;18935:21;;;18931:25;;18920:36;19007:21;;;19003:25;;;18992:36;17486:15;17917;;;17913:29;;;17909:37;;;17086:20;;;17075:32;;;18039:15;;;;17130:21;;17752:19;;;;18030:24;;;;19477:15;;15472:4067;-1:-1:-1;;;;15472:4067:0:o;14090:777::-;14152:11;-1:-1:-1;;;14180:1:0;:11;14176:78;;14214:3;14208:9;;;;14232:10;;;;:::i;:::-;;;14176:78;14273:5;14268:1;:10;14264:75;;14301:2;14295:8;;;;14318:9;;;;:::i;:::-;;;14264:75;14358:5;14353:1;:10;14349:75;;14386:2;14380:8;;;;14403:9;;;;:::i;:::-;;;14349:75;14443:5;14438:1;:10;14434:75;;14471:2;14465:8;;;;14488:9;;;;:::i;:::-;;;14434:75;14528:4;14523:1;:9;14519:72;;14555:1;14549:7;;;;14571:8;;;;:::i;:::-;;;14519:72;14610:4;14605:1;:9;14601:72;;14637:1;14631:7;;;;14653:8;;;;:::i;:::-;;;14601:72;14692:4;14687:1;:9;14683:72;;14719:1;14713:7;;;;14735:8;;;;:::i;:::-;;;14683:72;14774:4;14769:1;:9;14765:95;;14840:8;14847:1;14840:8;;:::i;14765:95::-;14090:777;;;:::o;20688:1188::-;20759:14;;;-1:-1:-1;;20878:1:0;20875;20868:20;20918:1;20915;20911:9;20902:18;;20970:5;20966:2;20963:13;20955:5;20951:2;20947:14;20943:34;20934:43;;;4320:4;21004:5;:14;21000:94;;21042:40;;-1:-1:-1;;;21042:40:0;;;;;738:25:1;;;711:18;;21042:40:0;592:177:1;21000:94:0;21106:17;21134:19;21214:5;21211:1;21208;21201:19;21188:32;;21263:18;21252:9;21249:33;21234:48;;21309:5;21318:1;21309:10;21305:157;;21392:11;4320:4;21375:5;:13;21374:29;21365:38;;21422:13;;;;;;21305:157;21718:11;21589:21;;;21585:39;21666:20;;;;21655:32;;;-1:-1:-1;;;21651:84:0;21556:202;;;;21781:13;21530:283;21508:350;;-1:-1:-1;20688:1188:0;;;;:::o;5012:8685::-;-1:-1:-1;;;5488:18:0;5484:22;;:26;5480:112;;5550:19;5541:28;5574:2;5540:36;5480:112;5614:18;5610:22;;:26;5606:112;;5676:19;5667:28;5700:2;5666:36;5606:112;5740:18;5736:22;;:26;5732:112;;5802:19;5793:28;5826:2;5792:36;5732:112;5866:18;5862:22;;:26;5858:112;;5928:19;5919:28;5952:2;5918:36;5858:112;5992:17;5988:21;;:25;5984:111;;6053:19;6044:28;6077:2;6043:36;5984:111;6117:17;6113:21;;:25;6109:111;;6178:19;6169:28;6202:2;6168:36;6109:111;6242:17;6238:21;;:25;6234:111;;6303:19;6294:28;6327:2;6293:36;6234:111;6367:17;6363:21;;:25;6359:111;;6428:19;6419:28;6452:2;6418:36;6359:111;6492:16;6488:20;;:24;6484:110;;6552:19;6543:28;6576:2;6542:36;6484:110;6616:16;6612:20;;:24;6608:110;;6676:19;6667:28;6700:2;6666:36;6608:110;6740:16;6736:20;;:24;6732:110;;6800:19;6791:28;6824:2;6790:36;6732:110;6864:16;6860:20;;:24;6856:110;;6924:19;6915:28;6948:2;6914:36;6856:110;6988:15;6984:19;;:23;6980:109;;7047:19;7038:28;7071:2;7037:36;6980:109;7111:15;7107:19;;:23;7103:109;;7170:19;7161:28;7194:2;7160:36;7103:109;7234:15;7230:19;;:23;7226:109;;7293:19;7284:28;7317:2;7283:36;7226:109;7357:15;7353:19;;:23;7349:109;;7416:19;7407:28;7440:2;7406:36;7349:109;7480:14;7476:18;;:22;7472:108;;7538:19;7529:28;7562:2;7528:36;7472:108;7602:14;7598:18;;:22;7594:108;;7660:19;7651:28;7684:2;7650:36;7594:108;7724:14;7720:18;;:22;7716:108;;7782:19;7773:28;7806:2;7772:36;7716:108;7846:14;7842:18;;:22;7838:108;;7904:19;7895:28;7928:2;7894:36;7838:108;7968:13;7964:17;;:21;7960:107;;8025:19;8016:28;8049:2;8015:36;7960:107;8089:13;8085:17;;:21;8081:107;;8146:19;8137:28;8170:2;8136:36;8081:107;8210:13;8206:17;;:21;8202:107;;8267:19;8258:28;8291:2;8257:36;8202:107;8331:13;8327:17;;:21;8323:107;;8388:19;8379:28;8412:2;8378:36;8323:107;8452:12;8448:16;;:20;8444:106;;8508:19;8499:28;8532:2;8498:36;8444:106;8572:12;8568:16;;:20;8564:106;;8628:19;8619:28;8652:2;8618:36;8564:106;8692:12;8688:16;;:20;8684:106;;8748:19;8739:28;8772:2;8738:36;8684:106;8812:12;8808:16;;:20;8804:106;;8868:19;8859:28;8892:2;8858:36;8804:106;8932:11;8928:15;;:19;8924:105;;8987:19;8978:28;9011:2;8977:36;8924:105;9051:11;9047:15;;:19;9043:105;;9106:19;9097:28;9130:2;9096:36;9043:105;9170:11;9166:15;;:19;9162:105;;9225:19;9216:28;9249:2;9215:36;9162:105;9289:11;9285:15;;:19;9281:105;;9344:19;9335:28;9368:2;9334:36;9281:105;9408:10;9404:14;;:18;9400:104;;9462:19;9453:28;9486:2;9452:36;9400:104;9526:10;9522:14;;:18;9518:104;;9580:19;9571:28;9604:2;9570:36;9518:104;9644:10;9640:14;;:18;9636:104;;9698:19;9689:28;9722:2;9688:36;9636:104;9762:10;9758:14;;:18;9754:104;;9816:19;9807:28;9840:2;9806:36;9754:104;9880:9;9876:13;;:17;9872:103;;9933:19;9924:28;9957:2;9923:36;9872:103;9997:9;9993:13;;:17;9989:103;;10050:19;10041:28;10074:2;10040:36;9989:103;10114:9;10110:13;;:17;10106:103;;10167:19;10158:28;10191:2;10157:36;10106:103;10231:9;10227:13;;:17;10223:103;;10284:19;10275:28;10308:2;10274:36;10223:103;10348:8;10344:12;;:16;10340:102;;10400:19;10391:28;10424:2;10390:36;10340:102;10464:8;10460:12;;:16;10456:102;;10516:19;10507:28;10540:2;10506:36;10456:102;10580:8;10576:12;;:16;10572:102;;10632:19;10623:28;10656:2;10622:36;10572:102;10696:8;10692:12;;:16;10688:102;;10748:19;10739:28;10772:2;10738:36;10688:102;10812:7;10808:11;;:15;10804:101;;10863:19;10854:28;10887:2;10853:36;10804:101;10927:7;10923:11;;:15;10919:101;;10978:19;10969:28;11002:2;10968:36;10919:101;11042:7;11038:11;;:15;11034:101;;11093:19;11084:28;11117:2;11083:36;11034:101;11157:7;11153:11;;:15;11149:101;;11208:19;11199:28;11232:2;11198:36;11149:101;11272:6;11268:10;;:14;11264:100;;11322:19;11313:28;11346:2;11312:36;11264:100;11386:6;11382:10;;:14;11378:100;;11436:19;11427:28;11460:2;11426:36;11378:100;11500:6;11496:10;;:14;11492:100;;11550:19;11541:28;11574:2;11540:36;11492:100;11614:6;11610:10;;:14;11606:100;;11664:19;11655:28;11688:2;11654:36;11606:100;11728:5;11724:9;;:13;11720:99;;11777:19;11768:28;11801:2;11767:36;11720:99;11841:5;11837:9;;:13;11833:99;;11890:19;11881:28;11914:2;11880:36;11833:99;11954:5;11950:9;;:13;11946:99;;12003:19;11994:28;12027:2;11993:36;11946:99;12067:5;12063:9;;:13;12059:99;;12116:19;12107:28;12140:2;12106:36;12059:99;12180:4;12176:8;;:12;12172:98;;12228:19;12219:28;12252:2;12218:36;12172:98;12292:4;12288:8;;:12;12284:98;;12340:19;12331:28;12364:2;12330:36;12284:98;12404:4;12400:8;;:12;12396:98;;12452:19;12443:28;12476:2;12442:36;12396:98;12516:4;12512:8;;:12;12508:98;;12564:19;12555:28;12588:2;12554:36;12508:98;12628:3;12624:7;;:11;12620:97;;12675:19;12666:28;12699:2;12665:36;12620:97;12739:3;12735:7;;:11;12731:97;;12786:19;12777:28;12810:2;12776:36;12731:97;12850:3;12846:7;;:11;12842:97;;12897:19;12888:28;12921:2;12887:36;12842:97;12961:3;12957:7;;:11;12953:97;;13008:19;12999:28;13032:2;12998:36;12953:97;4320:4;13620:15;13674:2;13669:7;;;;13662:3;:15;13650:28;;5012:8685::o;99147:305::-;99249:4;-1:-1:-1;;;;;;99286:40:0;;-1:-1:-1;;;99286:40:0;;:105;;-1:-1:-1;;;;;;;99343:48:0;;-1:-1:-1;;;99343:48:0;99286:105;:158;;;-1:-1:-1;;;;;;;;;;97863:40:0;;;99408:36;97754:157;52524:813;52580:13;-1:-1:-1;;;52610:1:0;:16;:36;;;;-1:-1:-1;;;52630:1:0;:16;52610:36;52606:110;;;52670:34;;-1:-1:-1;;;52670:34:0;;;;;;;;;;;52606:110;52753:10;52778;52812:1;52808;:5;:32;;52838:1;52808:32;;;52825:1;52824:2;;52808:32;52803:37;;52864:1;52860;:5;:32;;52890:1;52860:32;;;52877:1;52876:2;;52860:32;52855:37;;52909:12;52924:32;52949:2;52953;52924:24;:32::i;:::-;52909:47;;-1:-1:-1;;;;;52975:4:0;:27;52971:108;;;53030:33;;-1:-1:-1;;;53030:33:0;;;;;738:25:1;;;711:18;;53030:33:0;592:177:1;52971:108:0;-1:-1:-1;;53179:17:0;;;;53220;;53275:7;;;53193:1;53275:12;:43;;53313:4;53275:43;;;-1:-1:-1;;53290:13:0;;;53266:52;-1:-1:-1;;;;;52524:813:0:o;109027:174::-;109102:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;109102:29:0;-1:-1:-1;;;;;109102:29:0;;;;;;;;:24;;109156:23;109102:24;109156:14;:23::i;:::-;-1:-1:-1;;;;;109147:46:0;;;;;;;;;;;109027:174;;:::o;105339:348::-;105432:4;105134:16;;;:7;:16;;;;;;-1:-1:-1;;;;;105134:16:0;105449:73;;;;-1:-1:-1;;;105449:73:0;;36277:2:1;105449:73:0;;;36259:21:1;36316:2;36296:18;;;36289:30;36355:34;36335:18;;;36328:62;-1:-1:-1;;;36406:18:1;;;36399:42;36458:19;;105449:73:0;36075:408:1;105449:73:0;105533:13;105549:23;105564:7;105549:14;:23::i;:::-;105533:39;;105602:5;-1:-1:-1;;;;;105591:16:0;:7;-1:-1:-1;;;;;105591:16:0;;:51;;;;105635:7;-1:-1:-1;;;;;105611:31:0;:20;105623:7;105611:11;:20::i;:::-;-1:-1:-1;;;;;105611:31:0;;105591:51;:87;;;-1:-1:-1;;;;;;102431:25:0;;;102407:4;102431:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;105646:32;102310:164;108331:578;108490:4;-1:-1:-1;;;;;108463:31:0;:23;108478:7;108463:14;:23::i;:::-;-1:-1:-1;;;;;108463:31:0;;108455:85;;;;-1:-1:-1;;;108455:85:0;;36690:2:1;108455:85:0;;;36672:21:1;36729:2;36709:18;;;36702:30;36768:34;36748:18;;;36741:62;-1:-1:-1;;;36819:18:1;;;36812:39;36868:19;;108455:85:0;36488:405:1;108455:85:0;-1:-1:-1;;;;;108559:16:0;;108551:65;;;;-1:-1:-1;;;108551:65:0;;37100:2:1;108551:65:0;;;37082:21:1;37139:2;37119:18;;;37112:30;37178:34;37158:18;;;37151:62;-1:-1:-1;;;37229:18:1;;;37222:34;37273:19;;108551:65:0;36898:400:1;108551:65:0;108629:39;108650:4;108656:2;108660:7;108629:20;:39::i;:::-;108733:29;108750:1;108754:7;108733:8;:29::i;:::-;-1:-1:-1;;;;;108775:15:0;;;;;;:9;:15;;;;;:20;;108794:1;;108775:15;:20;;108794:1;;108775:20;:::i;:::-;;;;-1:-1:-1;;;;;;;108806:13:0;;;;;;:9;:13;;;;;:18;;108823:1;;108806:13;:18;;108823:1;;108806:18;:::i;:::-;;;;-1:-1:-1;;108835:16:0;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;108835:21:0;-1:-1:-1;;;;;108835:21:0;;;;;;;;;108874:27;;108835:16;;108874:27;;;;;;;108331:578;;;:::o;106029:110::-;106105:26;106115:2;106119:7;106105:26;;;;;;;;;;;;:9;:26::i;60564:173::-;60639:6;;;-1:-1:-1;;;;;60656:17:0;;;-1:-1:-1;;;;;;60656:17:0;;;;;;;60689:40;;60639:6;;;60656:17;60639:6;;60689:40;;60620:16;;60689:40;60609:128;60564:173;:::o;136191:752::-;136246:13;136477:5;136461:13;136497:10;;;136493:53;;-1:-1:-1;;136524:10:0;;;;;;;;;;;;-1:-1:-1;;;136524:10:0;;;;;136191:752;-1:-1:-1;136191:752:0:o;136493:53::-;136571:5;136556:12;136612:78;136619:9;;136612:78;;136645:8;;;;:::i;:::-;;-1:-1:-1;136668:10:0;;-1:-1:-1;136676:2:0;136668:10;;:::i;:::-;;;136612:78;;;136700:19;136732:6;136722:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;136722:17:0;;136700:39;;136750:154;136757:10;;136750:154;;136784:11;136794:1;136784:11;;:::i;:::-;;-1:-1:-1;136853:10:0;136861:2;136853:5;:10;:::i;:::-;136840:24;;:2;:24;:::i;:::-;136827:39;;136810:6;136817;136810:14;;;;;;;;:::i;:::-;;;;:56;-1:-1:-1;;;;;136810:56:0;;;;;;;;-1:-1:-1;136881:11:0;136890:2;136881:11;;:::i;:::-;;;136750:154;;;136928:6;136191:752;-1:-1:-1;;;;;136191:752:0:o;151393:265::-;151498:13;;:18;151490:43;;;;-1:-1:-1;;;151490:43:0;;;;;;;:::i;:::-;151544:32;151564:11;151544:19;:32::i;:::-;151636:13;;151592:58;;;34678:25:1;;;34734:2;34719:18;;34712:34;;;34762:18;;;34755:34;;;;151592:58:0;;34666:2:1;34651:18;151592:58:0;34460:335:1;142985:502:0;143032:13;143078:20;;143062:12;:36;143058:422;;-1:-1:-1;143124:25:0;;142985:502;:::o;143058:422::-;143247:20;143270:67;143292:20;;143277:12;:35;;;;:::i;:::-;143270:65;:67::i;:::-;143247:90;-1:-1:-1;143352:12:0;143367:41;:35;143388:13;143368:14;143247:90;143368:14;:::i;:::-;143367:20;;:35::i;:::-;:39;:41::i;:::-;143432:25;;143352:56;;-1:-1:-1;143432:36:0;;143352:56;143432:29;:36::i;151892:340::-;152015:41;152045:9;152015:22;:41::i;:::-;151997:15;:13;:15::i;:::-;:59;;;;:::i;:::-;151971:23;:85;152095:27;152116:5;152095:20;:27::i;:::-;152067:25;:55;152156:25;:23;:25::i;:::-;152133:20;:48;-1:-1:-1;;152212:12:0;152192:17;:32;151892:340::o;104417:315::-;104574:28;104584:4;104590:2;104594:7;104574:9;:28::i;:::-;104621:48;104644:4;104650:2;104654:7;104663:5;104621:22;:48::i;:::-;104613:111;;;;-1:-1:-1;;;104613:111:0;;;;;;;:::i;135475:458::-;135581:13;135733:5;135810:4;135886;135635:279;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;135607:318;;135475:458;;;;;:::o;119439:1607::-;119537:11;;119497:13;;119523:11;119563:8;;;119559:23;;-1:-1:-1;;119573:9:0;;;;;;;;;-1:-1:-1;119573:9:0;;;119439:1607;-1:-1:-1;119439:1607:0:o;119559:23::-;119634:18;119672:1;119661:7;:3;119667:1;119661:7;:::i;:::-;119660:13;;;;:::i;:::-;119655:19;;:1;:19;:::i;:::-;119634:40;-1:-1:-1;119732:19:0;119764:15;119634:40;119777:2;119764:15;:::i;:::-;119754:26;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119754:26:0;;119732:48;;119793:18;119814:5;;;;;;;;;;;;;;;;;119793:26;;119883:1;119876:5;119872:13;119928:2;119920:6;119916:15;119979:1;119947:777;120002:3;119999:1;119996:10;119947:777;;;120057:1;120100:12;;;;;120094:19;120195:4;120183:2;120179:14;;;;;120161:40;;120155:47;120304:2;120300:14;;;120296:25;;120282:40;;120276:47;120433:1;120429:13;;;120425:24;;120411:39;;120405:46;120553:16;;;;120539:31;;120533:38;120231:1;120227:11;;;120325:4;120272:58;;;120263:68;120356:11;;120401:57;;;120392:67;;;;120484:11;;120529:49;;120520:59;120608:3;120604:13;120637:22;;120707:1;120692:17;;;;120050:9;119947:777;;;119951:44;120756:1;120751:3;120747:11;120777:1;120772:84;;;;120875:1;120870:82;;;;120740:212;;120772:84;-1:-1:-1;;;;;120805:17:0;;120798:43;120772:84;;120870:82;-1:-1:-1;;;;;120903:17:0;;120896:41;120740:212;-1:-1:-1;;;120968:26:0;;;120975:6;119439:1607;-1:-1:-1;;;;119439:1607:0:o;150493:366::-;150636:16;150651:1;122200:4;150636:16;:::i;:::-;150621:32;;:11;:32;:::i;:::-;150605:13;:48;;;150722:1;150705:18;150701:68;;150756:1;150740:13;:17;150701:68;150799:4;150783:13;;:20;150779:73;;;150836:4;150820:13;:20;150493:366;:::o;78296:213::-;78422:14;;78398:48;;-1:-1:-1;;;78398:48:0;;-1:-1:-1;;;;;78422:14:0;;;78398:48;;;40232:51:1;40299:18;;;40292:34;;;78373:4:0;;78398:5;:23;;;;40205:18:1;;78398:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78390:89;;;;-1:-1:-1;;;78390:89:0;;40789:2:1;78390:89:0;;;40771:21:1;40828:2;40808:18;;;40801:30;40867;40847:18;;;40840:58;40915:18;;78390:89:0;40587:352:1;78390:89:0;-1:-1:-1;78497:4:0;;78296:213;-1:-1:-1;78296:213:0:o;76719:1053::-;76857:14;;76841:72;;-1:-1:-1;;;76841:72:0;;;;;34678:25:1;;;34719:18;;;34712:34;;;34762:18;;;34755:34;;;76811:17:0;;-1:-1:-1;;;;;76857:14:0;;76841:49;;34651:18:1;;76841:72:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;77164:15:0;77231:16;;;:6;:16;;;;;;;;;69213:51;;;;;41923:25:1;;;41964:18;;;41957:34;;;77224:4:0;42007:18:1;;;42000:60;42076:18;;;;42069:34;;;69213:51:0;;;;;;;;;;41895:19:1;;;;69213:51:0;;;69203:62;;;;;;;;;77687:16;;;;;;;69203:62;;-1:-1:-1;77687:27:0;;77712:1;77687:24;:27::i;:::-;77668:16;;;;:6;:16;;;;;:46;77732:32;77675:8;77756:7;69809:41;;;;;;;42627:19:1;;;;42662:12;;;42655:28;;;;69809:41:0;;;;;;;;;42699:12:1;;;;69809:41:0;;69799:52;;;;;;69685:174;49698:1935;49745:13;49780:1;49775;:6;49771:81;;49805:35;;-1:-1:-1;;;49805:35:0;;;;;738:25:1;;;711:18;;49805:35:0;592:177:1;49771:81:0;49944:11;27683:4;49974:1;:10;49970:329;;-1:-1:-1;50012:1:0;49970:329;;;-1:-1:-1;;50054:9:0;;50263:1;50224:37;50220:45;50215:50;;49970:329;50438:9;50450:46;27683:4;50485:1;:9;50450:26;:46::i;:::-;27683:4;50731:17;;;-1:-1:-1;50438:58:0;-1:-1:-1;50816:6:0;;;-1:-1:-1;;50898:10:0;;50894:71;;-1:-1:-1;;50936:13:0;;49698:1935;-1:-1:-1;49698:1935:0:o;50894:71::-;26674:4;51159:427;51207:1;51199:5;:9;51159:427;;;27683:4;51247:5;;;51246:15;;-1:-1:-1;51349:9:0;51344:14;;51340:231;;51447:15;;;;51550:1;51544:7;;;;;51340:231;51220:1;51210:11;51159:427;;;-1:-1:-1;;;51600:14:0;;49698:1935;-1:-1:-1;49698:1935:0:o;34523:1100::-;34570:13;34651:1;34647;:5;34643:973;;;-1:-1:-1;;34781:1:0;:26;34777:75;;;-1:-1:-1;34835:1:0;;34523:1100;-1:-1:-1;34523:1100:0:o;34777:75::-;35010:8;35016:1;35015:2;;35010:4;:8::i;:::-;35003:4;:15;;;;;:::i;:::-;;;14090:777;-1:-1:-1;;14090:777:0:o;34643:973::-;35172:6;35167:1;:11;35163:93;;35206:34;;-1:-1:-1;;;35206:34:0;;;;;738:25:1;;;711:18;;35206:34:0;592:177:1;35163:93:0;27683:4;35402:2;35388:16;;;35387:35;35567:21;35387:35;35567:12;:21::i;114640:589::-;-1:-1:-1;;;;;114846:18:0;;114842:187;;114881:40;114913:7;116056:10;:17;;116029:24;;;;:15;:24;;;;;:44;;;116084:24;;;;;;;;;;;;115952:164;114881:40;114842:187;;;114951:2;-1:-1:-1;;;;;114943:10:0;:4;-1:-1:-1;;;;;114943:10:0;;114939:90;;114970:47;115003:4;115009:7;114970:32;:47::i;:::-;-1:-1:-1;;;;;115043:16:0;;115039:183;;115076:45;115113:7;115076:36;:45::i;115039:183::-;115149:4;-1:-1:-1;;;;;115143:10:0;:2;-1:-1:-1;;;;;115143:10:0;;115139:83;;115170:40;115198:2;115202:7;115170:27;:40::i;106366:321::-;106496:18;106502:2;106506:7;106496:5;:18::i;:::-;106547:54;106578:1;106582:2;106586:7;106595:5;106547:22;:54::i;:::-;106525:154;;;;-1:-1:-1;;;106525:154:0;;;;;;;:::i;33295:670::-;33341:13;-1:-1:-1;;33473:1:0;:26;33469:67;;;-1:-1:-1;33523:1:0;;33295:670;-1:-1:-1;33295:670:0:o;33469:67::-;33643:22;33638:1;:27;33634:100;;33689:33;;-1:-1:-1;;;33689:33:0;;;;;738:25:1;;;711:18;;33689:33:0;592:177:1;33634:100:0;26570:20;33865:10;;33899:47;27683:4;26674;33905:31;;33904:41;33899:4;:47::i;145813:594::-;145871:14;145898:20;145921:38;145949:9;145921:23;;:27;;:38;;;;:::i;:::-;145898:61;;146057:25;146080:1;146057:22;:25::i;:::-;146041:13;:41;146037:363;;;146099:21;146149:53;:45;:38;146166:20;:13;:18;:20::i;:::-;146149:12;;:16;:38::i;:::-;:43;:45::i;:::-;27683:4;57761:9;;;57653:136;146149:53;146099:118;-1:-1:-1;146241:28:0;146099:118;146241:12;:28;:::i;146037:363::-;146376:12;146367:21;;146037:363;145887:520;145813:594;:::o;109766:799::-;109921:4;-1:-1:-1;;;;;109942:13:0;;88059:20;88107:8;109938:620;;109978:72;;-1:-1:-1;;;109978:72:0;;-1:-1:-1;;;;;109978:36:0;;;;;:72;;58418:10;;110029:4;;110035:7;;110044:5;;109978:72;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;109978:72:0;;;;;;;;-1:-1:-1;;109978:72:0;;;;;;;;;;;;:::i;:::-;;;109974:529;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110220:6;:13;110237:1;110220:18;110216:272;;110263:60;;-1:-1:-1;;;110263:60:0;;;;;;;:::i;110216:272::-;110438:6;110432:13;110423:6;110419:2;110415:15;110408:38;109974:529;-1:-1:-1;;;;;;110101:51:0;-1:-1:-1;;;110101:51:0;;-1:-1:-1;110094:58:0;;109938:620;-1:-1:-1;110542:4:0;109766:799;;;;;;:::o;61590:183::-;61652:7;;61684:5;61688:1;61684;:5;:::i;:::-;61672:17;;61713:1;61708;:6;;61700:46;;;;-1:-1:-1;;;61700:46:0;;42316:2:1;61700:46:0;;;42298:21:1;42355:2;42335:18;;;42328:30;42394:29;42374:18;;;42367:57;42441:18;;61700:46:0;42114:351:1;116743:988:0;117009:22;117059:1;117034:22;117051:4;117034:16;:22::i;:::-;:26;;;;:::i;:::-;117071:18;117092:26;;;:17;:26;;;;;;117009:51;;-1:-1:-1;117225:28:0;;;117221:328;;-1:-1:-1;;;;;117292:18:0;;117270:19;117292:18;;;:12;:18;;;;;;;;:34;;;;;;;;;117343:30;;;;;;:44;;;117460:30;;:17;:30;;;;;:43;;;117221:328;-1:-1:-1;117645:26:0;;;;:17;:26;;;;;;;;117638:33;;;-1:-1:-1;;;;;117689:18:0;;;;;:12;:18;;;;;:34;;;;;;;117682:41;116743:988::o;118026:1079::-;118304:10;:17;118279:22;;118304:21;;118324:1;;118304:21;:::i;:::-;118336:18;118357:24;;;:15;:24;;;;;;118730:10;:26;;118279:46;;-1:-1:-1;118357:24:0;;118279:46;;118730:26;;;;;;:::i;:::-;;;;;;;;;118708:48;;118794:11;118769:10;118780;118769:22;;;;;;;;:::i;:::-;;;;;;;;;;;;:36;;;;118874:28;;;:15;:28;;;;;;;:41;;;119046:24;;;;;119039:31;119081:10;:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;118097:1008;;;118026:1079;:::o;115530:221::-;115615:14;115632:20;115649:2;115632:16;:20::i;:::-;-1:-1:-1;;;;;115663:16:0;;;;;;;:12;:16;;;;;;;;:24;;;;;;;;:34;;;115708:26;;;:17;:26;;;;;;:35;;;;-1:-1:-1;115530:221:0:o;107023:382::-;-1:-1:-1;;;;;107103:16:0;;107095:61;;;;-1:-1:-1;;;107095:61:0;;43056:2:1;107095:61:0;;;43038:21:1;;;43075:18;;;43068:30;43134:34;43114:18;;;43107:62;43186:18;;107095:61:0;42854:356:1;107095:61:0;105110:4;105134:16;;;:7;:16;;;;;;-1:-1:-1;;;;;105134:16:0;:30;107167:58;;;;-1:-1:-1;;;107167:58:0;;43417:2:1;107167:58:0;;;43399:21:1;43456:2;43436:18;;;43429:30;43495;43475:18;;;43468:58;43543:18;;107167:58:0;43215:352:1;107167:58:0;107238:45;107267:1;107271:2;107275:7;107238:20;:45::i;:::-;-1:-1:-1;;;;;107296:13:0;;;;;;:9;:13;;;;;:18;;107313:1;;107296:13;:18;;107313:1;;107296:18;:::i;:::-;;;;-1:-1:-1;;107325:16:0;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;107325:21:0;-1:-1:-1;;;;;107325:21:0;;;;;;;;107364:33;;107325:16;;;107364:33;;107325:16;;107364:33;107023:382;;:::o;29971:573::-;30018:13;-1:-1:-1;;;;;30048:1:0;:21;30044:92;;;30093:31;;-1:-1:-1;;;30093:31:0;;;;;738:25:1;;;711:18;;30093:31:0;592:177:1;30044:92:0;27683:4;30190:9;;30171:16;30218:14;;;30214:312;;30262:1;30253:10;;30214:312;;;30414:9;30410:1;:13;30401:22;;30450:1;30446;:5;30442:69;;;-1:-1:-1;27683:4:0;30476:15;;29971:573;-1:-1:-1;29971:573:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:131:1;-1:-1:-1;;;;;;88:32:1;;78:43;;68:71;;135:1;132;125:12;150:245;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;954:258::-;1026:1;1036:113;1050:6;1047:1;1044:13;1036:113;;;1126:11;;;1120:18;1107:11;;;1100:39;1072:2;1065:10;1036:113;;;1167:6;1164:1;1161:13;1158:48;;;-1:-1:-1;;1202:1:1;1184:16;;1177:27;954:258::o;1217:::-;1259:3;1297:5;1291:12;1324:6;1319:3;1312:19;1340:63;1396:6;1389:4;1384:3;1380:14;1373:4;1366:5;1362:16;1340:63;:::i;:::-;1457:2;1436:15;-1:-1:-1;;1432:29:1;1423:39;;;;1464:4;1419:50;;1217:258;-1:-1:-1;;1217:258:1:o;1480:220::-;1629:2;1618:9;1611:21;1592:4;1649:45;1690:2;1679:9;1675:18;1667:6;1649:45;:::i;1705:180::-;1764:6;1817:2;1805:9;1796:7;1792:23;1788:32;1785:52;;;1833:1;1830;1823:12;1785:52;-1:-1:-1;1856:23:1;;1705:180;-1:-1:-1;1705:180:1:o;2098:173::-;2166:20;;-1:-1:-1;;;;;2215:31:1;;2205:42;;2195:70;;2261:1;2258;2251:12;2276:254;2344:6;2352;2405:2;2393:9;2384:7;2380:23;2376:32;2373:52;;;2421:1;2418;2411:12;2373:52;2444:29;2463:9;2444:29;:::i;:::-;2434:39;2520:2;2505:18;;;;2492:32;;-1:-1:-1;;;2276:254:1:o;2535:159::-;2602:20;;2662:6;2651:18;;2641:29;;2631:57;;2684:1;2681;2674:12;2699:184;2757:6;2810:2;2798:9;2789:7;2785:23;2781:32;2778:52;;;2826:1;2823;2816:12;2778:52;2849:28;2867:9;2849:28;:::i;2888:328::-;2965:6;2973;2981;3034:2;3022:9;3013:7;3009:23;3005:32;3002:52;;;3050:1;3047;3040:12;3002:52;3073:29;3092:9;3073:29;:::i;:::-;3063:39;;3121:38;3155:2;3144:9;3140:18;3121:38;:::i;:::-;3111:48;;3206:2;3195:9;3191:18;3178:32;3168:42;;2888:328;;;;;:::o;3410:127::-;3471:10;3466:3;3462:20;3459:1;3452:31;3502:4;3499:1;3492:15;3526:4;3523:1;3516:15;3542:251;3614:2;3608:9;;;3644:15;;3689:18;3674:34;;3710:22;;;3671:62;3668:88;;;3736:18;;:::i;:::-;3772:2;3765:22;3542:251;:::o;3798:275::-;3869:2;3863:9;3934:2;3915:13;;-1:-1:-1;;3911:27:1;3899:40;;3969:18;3954:34;;3990:22;;;3951:62;3948:88;;;4016:18;;:::i;:::-;4052:2;4045:22;3798:275;;-1:-1:-1;3798:275:1:o;4078:187::-;4142:4;4175:18;4167:6;4164:30;4161:56;;;4197:18;;:::i;:::-;-1:-1:-1;4242:1:1;4238:14;4254:4;4234:25;;4078:187::o;4270:114::-;4354:4;4347:5;4343:16;4336:5;4333:27;4323:55;;4374:1;4371;4364:12;4389:130;4455:20;;4484:29;4455:20;4484:29;:::i;4524:187::-;4573:4;4606:18;4598:6;4595:30;4592:56;;;4628:18;;:::i;:::-;-1:-1:-1;4694:2:1;4673:15;-1:-1:-1;;4669:29:1;4700:4;4665:40;;4524:187::o;4716:338::-;4781:5;4810:53;4826:36;4855:6;4826:36;:::i;:::-;4810:53;:::i;:::-;4801:62;;4886:6;4879:5;4872:21;4926:3;4917:6;4912:3;4908:16;4905:25;4902:45;;;4943:1;4940;4933:12;4902:45;4992:6;4987:3;4980:4;4973:5;4969:16;4956:43;5046:1;5039:4;5030:6;5023:5;5019:18;5015:29;5008:40;4716:338;;;;;:::o;5059:222::-;5102:5;5155:3;5148:4;5140:6;5136:17;5132:27;5122:55;;5173:1;5170;5163:12;5122:55;5195:80;5271:3;5262:6;5249:20;5242:4;5234:6;5230:17;5195:80;:::i;5286:1902::-;5417:6;5425;5433;5486:2;5474:9;5465:7;5461:23;5457:32;5454:52;;;5502:1;5499;5492:12;5454:52;5542:9;5529:23;5571:18;5612:2;5604:6;5601:14;5598:34;;;5628:1;5625;5618:12;5598:34;5666:6;5655:9;5651:22;5641:32;;5692:4;5732:7;5727:2;5723;5719:11;5715:25;5705:53;;5754:1;5751;5744:12;5705:53;5790:2;5777:16;5812:4;5836:64;5852:47;5896:2;5852:47;:::i;5836:64::-;5934:15;;;6016:1;6012:10;;;;6004:19;;6000:28;;;5965:12;;;;6040:19;;;6037:39;;;6072:1;6069;6062:12;6037:39;6096:11;;;;6116:812;6132:6;6127:3;6124:15;6116:812;;;6216:7;6211:2;6206:3;6202:12;6198:26;6188:124;;6266:1;6295:2;6291;6284:14;6188:124;6338:22;;:::i;:::-;6386:5;6429:4;6424:3;6420:14;6463:7;6453:8;6450:21;6447:111;;;6512:1;6541:2;6537;6530:14;6447:111;6584:3;6600:255;6618:8;6611:5;6608:19;6600:255;;;6712:5;6699:19;6735:29;6758:5;6735:29;:::i;:::-;6781:20;;6827:14;;;;6639;;6600:255;;;-1:-1:-1;;6868:18:1;;-1:-1:-1;6158:4:1;6149:14;;;;;6906:12;;;;6116:812;;;6947:5;-1:-1:-1;6971:36:1;;-1:-1:-1;6988:18:1;;;6971:36;:::i;:::-;6961:46;;;;;7060:4;7049:9;7045:20;7032:34;7016:50;;7091:2;7081:8;7078:16;7075:36;;;7107:1;7104;7097:12;7075:36;;7130:52;7174:7;7163:8;7152:9;7148:24;7130:52;:::i;:::-;7120:62;;;5286:1902;;;;;:::o;8167:186::-;8226:6;8279:2;8267:9;8258:7;8254:23;8250:32;8247:52;;;8295:1;8292;8285:12;8247:52;8318:29;8337:9;8318:29;:::i;8625:248::-;8693:6;8701;8754:2;8742:9;8733:7;8729:23;8725:32;8722:52;;;8770:1;8767;8760:12;8722:52;-1:-1:-1;;8793:23:1;;;8863:2;8848:18;;;8835:32;;-1:-1:-1;8625:248:1:o;8878:118::-;8964:5;8957:13;8950:21;8943:5;8940:32;8930:60;;8986:1;8983;8976:12;9001:315;9066:6;9074;9127:2;9115:9;9106:7;9102:23;9098:32;9095:52;;;9143:1;9140;9133:12;9095:52;9166:29;9185:9;9166:29;:::i;:::-;9156:39;;9245:2;9234:9;9230:18;9217:32;9258:28;9280:5;9258:28;:::i;:::-;9305:5;9295:15;;;9001:315;;;;;:::o;9321:667::-;9416:6;9424;9432;9440;9493:3;9481:9;9472:7;9468:23;9464:33;9461:53;;;9510:1;9507;9500:12;9461:53;9533:29;9552:9;9533:29;:::i;:::-;9523:39;;9581:38;9615:2;9604:9;9600:18;9581:38;:::i;:::-;9571:48;;9666:2;9655:9;9651:18;9638:32;9628:42;;9721:2;9710:9;9706:18;9693:32;9748:18;9740:6;9737:30;9734:50;;;9780:1;9777;9770:12;9734:50;9803:22;;9856:4;9848:13;;9844:27;-1:-1:-1;9834:55:1;;9885:1;9882;9875:12;9834:55;9908:74;9974:7;9969:2;9956:16;9951:2;9947;9943:11;9908:74;:::i;:::-;9898:84;;;9321:667;;;;;;;:::o;9993:260::-;10061:6;10069;10122:2;10110:9;10101:7;10097:23;10093:32;10090:52;;;10138:1;10135;10128:12;10090:52;10161:29;10180:9;10161:29;:::i;:::-;10151:39;;10209:38;10243:2;10232:9;10228:18;10209:38;:::i;:::-;10199:48;;9993:260;;;;;:::o;10258:313::-;10322:6;10330;10383:2;10371:9;10362:7;10358:23;10354:32;10351:52;;;10399:1;10396;10389:12;10351:52;10422:28;10440:9;10422:28;:::i;10576:737::-;10628:5;10681:3;10674:4;10666:6;10662:17;10658:27;10648:55;;10699:1;10696;10689:12;10648:55;10735:6;10722:20;10761:4;10785:64;10801:47;10845:2;10801:47;:::i;10785:64::-;10883:15;;;10969:1;10965:10;;;;10953:23;;10949:32;;;10914:12;;;;10993:15;;;10990:35;;;11021:1;11018;11011:12;10990:35;11057:2;11049:6;11045:15;11069:215;11085:6;11080:3;11077:15;11069:215;;;11165:3;11152:17;11182:29;11205:5;11182:29;:::i;:::-;11224:18;;11262:12;;;;11102;;11069:215;;;-1:-1:-1;11302:5:1;10576:737;-1:-1:-1;;;;;;10576:737:1:o;11318:1140::-;11434:6;11442;11495:2;11483:9;11474:7;11470:23;11466:32;11463:52;;;11511:1;11508;11501:12;11463:52;11551:9;11538:23;11580:18;11621:2;11613:6;11610:14;11607:34;;;11637:1;11634;11627:12;11607:34;11675:6;11664:9;11660:22;11650:32;;11720:7;11713:4;11709:2;11705:13;11701:27;11691:55;;11742:1;11739;11732:12;11691:55;11778:2;11765:16;11800:4;11824:64;11840:47;11884:2;11840:47;:::i;11824:64::-;11922:15;;;12004:1;12000:10;;;;11992:19;;11988:28;;;11953:12;;;;12028:19;;;12025:39;;;12060:1;12057;12050:12;12025:39;12084:11;;;;12104:142;12120:6;12115:3;12112:15;12104:142;;;12186:17;;12174:30;;12137:12;;;;12224;;;;12104:142;;;12265:5;-1:-1:-1;;12308:18:1;;12295:32;;-1:-1:-1;;12339:16:1;;;12336:36;;;12368:1;12365;12358:12;12336:36;;12391:61;12444:7;12433:8;12422:9;12418:24;12391:61;:::i;:::-;12381:71;;;11318:1140;;;;;:::o;12463:127::-;12524:10;12519:3;12515:20;12512:1;12505:31;12555:4;12552:1;12545:15;12579:4;12576:1;12569:15;12595:125;12635:4;12663:1;12660;12657:8;12654:34;;;12668:18;;:::i;:::-;-1:-1:-1;12705:9:1;;12595:125::o;12725:136::-;12760:3;-1:-1:-1;;;12781:22:1;;12778:48;;12806:18;;:::i;:::-;-1:-1:-1;12846:1:1;12842:13;;12725:136::o;12866:380::-;12945:1;12941:12;;;;12988;;;13009:61;;13063:4;13055:6;13051:17;13041:27;;13009:61;13116:2;13108:6;13105:14;13085:18;13082:38;13079:161;;13162:10;13157:3;13153:20;13150:1;13143:31;13197:4;13194:1;13187:15;13225:4;13222:1;13215:15;14491:338;14693:2;14675:21;;;14732:2;14712:18;;;14705:30;-1:-1:-1;;;14766:2:1;14751:18;;14744:44;14820:2;14805:18;;14491:338::o;14834:336::-;15036:2;15018:21;;;15075:2;15055:18;;;15048:30;-1:-1:-1;;;15109:2:1;15094:18;;15087:42;15161:2;15146:18;;14834:336::o;15175:127::-;15236:10;15231:3;15227:20;15224:1;15217:31;15267:4;15264:1;15257:15;15291:4;15288:1;15281:15;15307:247;15375:6;15428:2;15416:9;15407:7;15403:23;15399:32;15396:52;;;15444:1;15441;15434:12;15396:52;15476:9;15470:16;15495:29;15518:5;15495:29;:::i;16066:636::-;16146:6;16199:2;16187:9;16178:7;16174:23;16170:32;16167:52;;;16215:1;16212;16205:12;16167:52;16248:9;16242:16;16281:18;16273:6;16270:30;16267:50;;;16313:1;16310;16303:12;16267:50;16336:22;;16389:4;16381:13;;16377:27;-1:-1:-1;16367:55:1;;16418:1;16415;16408:12;16367:55;16447:2;16441:9;16472:49;16488:32;16517:2;16488:32;:::i;16472:49::-;16544:2;16537:5;16530:17;16584:7;16579:2;16574;16570;16566:11;16562:20;16559:33;16556:53;;;16605:1;16602;16595:12;16556:53;16618:54;16669:2;16664;16657:5;16653:14;16648:2;16644;16640:11;16618:54;:::i;17217:858::-;17492:3;17530:6;17524:13;17546:53;17592:6;17587:3;17580:4;17572:6;17568:17;17546:53;:::i;:::-;17662:13;;17621:16;;;;17684:57;17662:13;17621:16;17718:4;17706:17;;17684:57;:::i;:::-;17808:13;;17763:20;;;17830:57;17808:13;17763:20;17864:4;17852:17;;17830:57;:::i;:::-;17954:13;;17909:20;;;17976:57;17954:13;17909:20;18010:4;17998:17;;17976:57;:::i;:::-;18049:20;;17217:858;-1:-1:-1;;;;;;17217:858:1:o;18080:356::-;18282:2;18264:21;;;18301:18;;;18294:30;18360:34;18355:2;18340:18;;18333:62;18427:2;18412:18;;18080:356::o;18441:413::-;18643:2;18625:21;;;18682:2;18662:18;;;18655:30;18721:34;18716:2;18701:18;;18694:62;-1:-1:-1;;;18787:2:1;18772:18;;18765:47;18844:3;18829:19;;18441:413::o;20284:952::-;20544:13;;20487:3;;20518;;20597:4;20624:15;;;20487:3;;20688:521;20704:6;20699:3;20696:15;20688:521;;;20767:13;;20806:5;20893:1;20907:216;20923:4;20918:3;20915:13;20907:216;;;21000:15;;21017:4;20996:26;20982:41;;21092:17;;;;21049:14;;;;20947:1;20938:11;20907:216;;;-1:-1:-1;;;21156:4:1;21145:16;;;;;21184:15;;;;20730:1;20721:11;20688:521;;;-1:-1:-1;21225:5:1;;20284:952;-1:-1:-1;;;;;;;20284:952:1:o;21583:224::-;21622:3;21650:6;21683:2;21680:1;21676:10;21713:2;21710:1;21706:10;21744:3;21740:2;21736:12;21731:3;21728:21;21725:47;;;21752:18;;:::i;:::-;21788:13;;21583:224;-1:-1:-1;;;;21583:224:1:o;21812:175::-;21849:3;21893:4;21886:5;21882:16;21922:4;21913:7;21910:17;21907:43;;21930:18;;:::i;:::-;21979:1;21966:15;;21812:175;-1:-1:-1;;21812:175:1:o;21992:217::-;22031:4;22060:6;22116:10;;;;22086;;22138:12;;;22135:38;;;22153:18;;:::i;:::-;22190:13;;21992:217;-1:-1:-1;;;21992:217:1:o;22656:204::-;22694:3;22730:4;22727:1;22723:12;22762:4;22759:1;22755:12;22797:3;22791:4;22787:14;22782:3;22779:23;22776:49;;;22805:18;;:::i;:::-;22841:13;;22656:204;-1:-1:-1;;;22656:204:1:o;22865:265::-;22904:3;22932:9;;;22957:10;;-1:-1:-1;;;;;22976:27:1;;;22969:35;;22953:52;22950:78;;;23008:18;;:::i;:::-;-1:-1:-1;;;23055:19:1;;;23048:27;;23040:36;;23037:62;;;23079:18;;:::i;:::-;-1:-1:-1;;23115:9:1;;22865:265::o;25392:128::-;25432:3;25463:1;25459:6;25456:1;25453:13;25450:39;;;25469:18;;:::i;:::-;-1:-1:-1;25505:9:1;;25392:128::o;25525:127::-;25586:10;25581:3;25577:20;25574:1;25567:31;25617:4;25614:1;25607:15;25641:4;25638:1;25631:15;25657:112;25689:1;25715;25705:35;;25720:18;;:::i;:::-;-1:-1:-1;25754:9:1;;25657:112::o;25774:1641::-;26241:3;26279:6;26273:13;26305:4;26318:51;26362:6;26357:3;26352:2;26344:6;26340:15;26318:51;:::i;:::-;26432:13;;26391:16;;;;26454:55;26432:13;26391:16;26476:15;;;26454:55;:::i;:::-;26576:13;;26531:20;;;26598:55;26576:13;26531:20;26620:15;;;26598:55;:::i;:::-;26720:13;;26675:20;;;26742:55;26720:13;26675:20;26764:15;;;26742:55;:::i;:::-;26864:13;;26819:20;;;26886:55;26864:13;26819:20;26908:15;;;26886:55;:::i;:::-;27008:13;;26963:20;;;27030:55;27008:13;26963:20;27052:15;;;27030:55;:::i;:::-;27152:13;;27107:20;;;27174:55;27152:13;27107:20;27196:15;;;27174:55;:::i;:::-;27296:13;;27251:20;;;27318:55;27296:13;27251:20;27340:15;;;27318:55;:::i;:::-;27389:20;;;;;25774:1641;-1:-1:-1;;;;;;;;;;;25774:1641:1:o;28134:168::-;28174:7;28240:1;28236;28232:6;28228:14;28225:1;28222:21;28217:1;28210:9;28203:17;28199:45;28196:71;;;28247:18;;:::i;:::-;-1:-1:-1;28287:9:1;;28134:168::o;28307:120::-;28347:1;28373;28363:35;;28378:18;;:::i;:::-;-1:-1:-1;28412:9:1;;28307:120::o;30466:135::-;30505:3;30526:17;;;30523:43;;30546:18;;:::i;:::-;-1:-1:-1;30593:1:1;30582:13;;30466:135::o;30606:664::-;30833:3;30871:6;30865:13;30887:53;30933:6;30928:3;30921:4;30913:6;30909:17;30887:53;:::i;:::-;31003:13;;30962:16;;;;31025:57;31003:13;30962:16;31059:4;31047:17;;31025:57;:::i;:::-;31149:13;;31104:20;;;31171:57;31149:13;31104:20;31205:4;31193:17;;31171:57;:::i;:::-;31244:20;;30606:664;-1:-1:-1;;;;;30606:664:1:o;31275:1485::-;-1:-1:-1;;;31924:45:1;;31992:13;;31906:3;;32014:62;31992:13;32064:2;32055:12;;32048:4;32036:17;;32014:62;:::i;:::-;32140:66;32135:2;32095:16;;;32127:11;;;32120:87;-1:-1:-1;;;32231:2:1;32223:11;;32216:43;32284:13;;32306:63;32284:13;32355:2;32347:11;;32340:4;32328:17;;32306:63;:::i;:::-;32434:66;32429:2;32388:17;;;;32421:11;;;32414:87;-1:-1:-1;;;32525:2:1;32517:11;;32510:27;32562:13;;32584:63;32562:13;32633:2;32625:11;;32618:4;32606:17;;32584:63;:::i;:::-;-1:-1:-1;;;32707:2:1;32666:17;;;;32699:11;;;32692:35;32751:2;32743:11;;31275:1485;-1:-1:-1;;;;;31275:1485:1:o;32765:448::-;33027:31;33022:3;33015:44;32997:3;33088:6;33082:13;33104:62;33159:6;33154:2;33149:3;33145:12;33138:4;33130:6;33126:17;33104:62;:::i;:::-;33186:16;;;;33204:2;33182:25;;32765:448;-1:-1:-1;;32765:448:1:o;33218:421::-;-1:-1:-1;;;33475:3:1;33468:19;33450:3;33516:6;33510:13;33532:61;33586:6;33582:1;33577:3;33573:11;33566:4;33558:6;33554:17;33532:61;:::i;:::-;33613:16;;;;33631:1;33609:24;;33218:421;-1:-1:-1;;33218:421:1:o;33644:470::-;33823:3;33861:6;33855:13;33877:53;33923:6;33918:3;33911:4;33903:6;33899:17;33877:53;:::i;:::-;33993:13;;33952:16;;;;34015:57;33993:13;33952:16;34049:4;34037:17;;34015:57;:::i;34119:336::-;34321:2;34303:21;;;34360:2;34340:18;;;34333:30;-1:-1:-1;;;34394:2:1;34379:18;;34372:42;34446:2;34431:18;;34119:336::o;37627:414::-;37829:2;37811:21;;;37868:2;37848:18;;;37841:30;37907:34;37902:2;37887:18;;37880:62;-1:-1:-1;;;37973:2:1;37958:18;;37951:48;38031:3;38016:19;;37627:414::o;38182:1871::-;39045:66;39040:3;39033:79;39151:38;39146:3;39142:48;39137:2;39132:3;39128:12;39121:70;39015:3;39220:6;39214:13;39236:60;39289:6;39284:2;39279:3;39275:12;39270:2;39262:6;39258:15;39236:60;:::i;:::-;-1:-1:-1;;;39390:2:1;39315:16;;;39382:11;;;39375:23;;;39427:66;39422:2;39414:11;;39407:87;-1:-1:-1;;;39551:2:1;39543:11;;39536:23;;;39584:13;;39606:61;39584:13;39653:2;39645:11;;39640:2;39628:15;;39606:61;:::i;:::-;39727:2;39686:17;;39719:11;;;39712:23;;;;39764:66;39759:2;39751:11;;39744:87;39855:3;39847:12;;39840:24;39889:13;;39911:62;39889:13;39958:3;39950:12;;39945:2;39933:15;;39911:62;:::i;:::-;39989:58;40042:3;40031:8;40027:2;40023:17;40019:27;-1:-1:-1;;;38111:33:1;;38169:1;38160:11;;38046:131;39989:58;39982:65;38182:1871;-1:-1:-1;;;;;;;38182:1871:1:o;40337:245::-;40404:6;40457:2;40445:9;40436:7;40432:23;40428:32;40425:52;;;40473:1;40470;40463:12;40425:52;40505:9;40499:16;40524:28;40546:5;40524:28;:::i;40944:489::-;-1:-1:-1;;;;;41213:15:1;;;41195:34;;41265:15;;41260:2;41245:18;;41238:43;41312:2;41297:18;;41290:34;;;41360:3;41355:2;41340:18;;41333:31;;;41138:4;;41381:46;;41407:19;;41399:6;41381:46;:::i;:::-;41373:54;40944:489;-1:-1:-1;;;;;;40944:489:1:o;41438:249::-;41507:6;41560:2;41548:9;41539:7;41535:23;41531:32;41528:52;;;41576:1;41573;41566:12;41528:52;41608:9;41602:16;41627:30;41651:5;41627:30;:::i;42722:127::-;42783:10;42778:3;42774:20;42771:1;42764:31;42814:4;42811:1;42804:15;42838:4;42835:1;42828:15

Swarm Source

ipfs://2368e0dc7711ed437a6113708eefa64ae68ccb1c529d3cb7b5d18ec918aec2ad
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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