Contract 0xcf77a3ba9a5ca399b7c97c74d54e5b1beb874e43 17

 
Txn Hash Method
Block
From
To
Value
0x04a0f10667cf49f15599b6e332c6086f7c1b079bb6e5458670fde6c59dc262feSwap Exact Token...132304182024-04-16 6:49:433 secs ago0x0c3eeaacae83a02006c5bb467642469079132479 IN  Aerodrome: Router0 ETH0.00000977020.018768941
0xcf2e0eb544bda780d11dc8ba9cbf324a3188c94f03c1d0c6ca62c8c12aefc412Add Liquidity132304122024-04-16 6:49:3115 secs ago0xdd022225a0e7e65de8e1b112874d6407916773ff IN  Aerodrome: Router0 ETH0.0000039447030.019699808
0x8bf8cc298b2d3145c67760d649d384059a37f3b7230bf7e827a46632728ceeedSwap Exact Token...132304102024-04-16 6:49:2719 secs ago0xe14a13b8eb93b6569a748ea57a1a97025fc82be9 IN  Aerodrome: Router0 ETH0.0000037078510.018783908
0x2b52a9fd044fa97e7082f4dae9083542600802ab2e9703e596f83a554a470361Swap Exact ETH F...132304102024-04-16 6:49:2719 secs ago0xb195b5bc233d406ffe6902af70c9171f0a228863 IN  Aerodrome: Router0.02 ETH0.0000094555950.018783908
0xf956ab37754699ba68b4ad301f21bb2b75eb2beb29eba35f64d7b4b62e06f912Add Liquidity132304102024-04-16 6:49:2719 secs ago0x4443327b5fee07fc80e227561477e9ac733d653a IN  Aerodrome: Router0 ETH0.0000040217040.0218
0x3f9c2778c1ba5c5b2a7e0ea4a8d21b5987878922989275f91e89f4c1debfa86cSwap Exact Token...132304082024-04-16 6:49:2323 secs ago0x5890912badac73a337fbe59f0dd8283cc8368c4b IN  Aerodrome: Router0 ETH0.0000062640350.0217
0x3a0bc947fb113749ab1268b74ccdf182f6e2d383b354036e7934a3159dbb7100Swap Exact ETH F...132304052024-04-16 6:49:1729 secs ago0xe244b3bdd6f452e03958f76d2b9c66ccd9c53288 IN  Aerodrome: Router0.0016 ETH0.0000039833190.018782301
0x9d750cba6582d7f6c144945c25818f1d5b5a35b23277403f223a4261b99dae55Swap Exact ETH F...132304042024-04-16 6:49:1531 secs ago0x2a962a15fc13b1497969135dcb8945325fe3330c IN  Aerodrome: Router0.00001 ETH0.0000118844660.018783448
0xc638985f8f8689da3f17823262e3846e85a441111514c6ae6d6f9ad94c1fa856Swap Exact Token...132304042024-04-16 6:49:1531 secs ago0x9d7bd45ae3c2bba8f8c7b85d2764873f4a07007a IN  Aerodrome: Router0 ETH0.0000039435760.019683448
0xbadf3b063698d1e0a96673efcb5ecab4c134a86924408e453d46bf2c6dea1536Swap Exact Token...132304032024-04-16 6:49:1333 secs ago0x11f22450d009ed868c562b00b3c696d25f3101e9 IN  Aerodrome: Router0 ETH0.0000043080160.019683808
0x27d3c652f4f05484eadc819798450de62f81f5a50818dcda1b0c8e6f50dddd12Remove Liquidity132304012024-04-16 6:49:0937 secs ago0x9d5e48babfe284ef420a814c9da774c9f71ee1b2 IN  Aerodrome: Router0 ETH0.0000035003850.018662181
0x5a6e79deda6cde0716dedae21b33318227491aef5ee7c0aa889249c43f9345d5Swap Exact Token...132303962024-04-16 6:48:5947 secs ago0x9a58350d44031c2215c9d9b2223d5e399bb43734 IN  Aerodrome: Router0 ETH0.0000038171130.018710088
0xe8f513615ab94143a9dac19e1ea55879d21c2c9287e57d3e1cc7151f1236048bSwap Exact Token...132303962024-04-16 6:48:5947 secs ago0x1df428833f2c9fb1ef098754e5d710432450d706 IN  Aerodrome: Router0 ETH0.0000040140230.018710088
0xf75ff13e28327a3eff0a8d123f508e01f30599500aa000d18b93b9f255734c14Swap Exact Token...132303952024-04-16 6:48:5749 secs ago0x5481b6fd3a725b36db0869cdedaaf1892e4c3da5 IN  Aerodrome: Router0 ETH0.0000059566070.01859194
0xdc60d1353d07d5578945678434128cdf11a6b6b708a00a9ad2ee83b45dba76a2Swap Exact ETH F...132303952024-04-16 6:48:5749 secs ago0x26923cc8f15f7efd418702bb1f51c25730f8eb2a IN  Aerodrome: Router0.034 ETH0.0000036583760.01859194
0x9c4e68641f369dde8a42152a21df5356a02f2a15a0e21f8217df34824ab51fdeSwap Exact Token...132303952024-04-16 6:48:5749 secs ago0x873ad68712498b2430906baa29c90b4d492511c7 IN  Aerodrome: Router0 ETH0.0000037932570.01859194
0x960724a00b405b311dd54bdddeb206003cf6c4b9ddc601d01addf28f60399985Swap Exact Token...132303952024-04-16 6:48:5749 secs ago0xe14a13b8eb93b6569a748ea57a1a97025fc82be9 IN  Aerodrome: Router0 ETH0.0000078742040.01859194
0x955b6e77f392b35ca16efbf435e93fd748a202f272ff9af6ce6f71a049ebac5fSwap Exact Token...132303942024-04-16 6:48:5551 secs ago0x50d113e49cb3a9d275bf4335b4ff13d4bad2b969 IN  Aerodrome: Router0 ETH0.0000100196410.018636937
0xb9294f7acac602253338d82ca2ac2c28bfb86a49471aa72df528d6c2aac3c308Swap Exact ETH F...132303932024-04-16 6:48:5353 secs ago0x5a11aa3a02b166a4607eddaebf5243e7aa793106 IN  Aerodrome: Router0.1 ETH0.0000035886780.018627436
0x15e59aae421cead4aa754079254bc3719b3c639ec6459d8b3c64e802b609b08fSwap Exact Token...132303872024-04-16 6:48:411 min ago0xe99d9cb3afd16ee9385af0d2eb57a79927b4b693 IN  Aerodrome: Router0 ETH0.0004344150482.118536226
0xa0b82be525abe4aae6c5a82b14bc44459f194a459b4d9d2920781f39a71f35f1Add Liquidity132303842024-04-16 6:48:351 min ago0x372d3d790c4691593b66d96aa96681c60ff5b5ae IN  Aerodrome: Router0 ETH0.0000055610240.0215
0xec9f7dddf3376e4308a2f59d8d51ca20d585cea33d562cc9e93898a8349b0318Swap Exact ETH F...132303812024-04-16 6:48:291 min ago0xc5c2a427681ed6ab368bcf4b41ad60b9e0110177 IN  Aerodrome: Router0.29 ETH0.000005908640.018609505
0x5df4edb4e6c71ff6780b932896fbb4014b2c2f02e0bc33e738f5ce3240adf536Swap Exact Token...132303802024-04-16 6:48:271 min ago0x04526c8eb172cee7814aef2ae02046b71fdf9125 IN  Aerodrome: Router0 ETH0.0000048282620.0216
0x788f1256df35db8c98a843172eefbda82140c313561eedc4523b7b336a6255edRemove Liquidity132303782024-04-16 6:48:231 min ago0x170d2ea8f593fcabdb353dbf92fc9e4a417d688c IN  Aerodrome: Router0 ETH0.0000041134750.018665035
0xa2096e0b080eb88a5f883e23963d8cbaa790fc30d00da461f129026394e25418Swap Exact Token...132303762024-04-16 6:48:191 min ago0x9d7bd45ae3c2bba8f8c7b85d2764873f4a07007a IN  Aerodrome: Router0 ETH0.0000042720510.019512815
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x04a0f10667cf49f15599b6e332c6086f7c1b079bb6e5458670fde6c59dc262fe132304182024-04-16 6:49:433 secs ago Aerodrome: Router0x0c3eeaacae83a02006c5bb4676424690791324790.009960165876249839 ETH
0x04a0f10667cf49f15599b6e332c6086f7c1b079bb6e5458670fde6c59dc262fe132304182024-04-16 6:49:433 secs ago Wrapped Ether Aerodrome: Router0.009960165876249839 ETH
0x2b52a9fd044fa97e7082f4dae9083542600802ab2e9703e596f83a554a470361132304102024-04-16 6:49:2719 secs ago Aerodrome: RouterWrapped Ether0.02 ETH
0x3a0bc947fb113749ab1268b74ccdf182f6e2d383b354036e7934a3159dbb7100132304052024-04-16 6:49:1729 secs ago Aerodrome: RouterWrapped Ether0.0016 ETH
0x9d750cba6582d7f6c144945c25818f1d5b5a35b23277403f223a4261b99dae55132304042024-04-16 6:49:1531 secs ago Aerodrome: RouterWrapped Ether0.00001 ETH
0xc638985f8f8689da3f17823262e3846e85a441111514c6ae6d6f9ad94c1fa856132304042024-04-16 6:49:1531 secs ago Aerodrome: Router0x9d7bd45ae3c2bba8f8c7b85d2764873f4a07007a0.021684754617111055 ETH
0xc638985f8f8689da3f17823262e3846e85a441111514c6ae6d6f9ad94c1fa856132304042024-04-16 6:49:1531 secs ago Wrapped Ether Aerodrome: Router0.021684754617111055 ETH
0x5a6e79deda6cde0716dedae21b33318227491aef5ee7c0aa889249c43f9345d5132303962024-04-16 6:48:5947 secs ago Aerodrome: Router0x9a58350d44031c2215c9d9b2223d5e399bb437340.020731033153461066 ETH
0x5a6e79deda6cde0716dedae21b33318227491aef5ee7c0aa889249c43f9345d5132303962024-04-16 6:48:5947 secs ago Wrapped Ether Aerodrome: Router0.020731033153461066 ETH
0xdc60d1353d07d5578945678434128cdf11a6b6b708a00a9ad2ee83b45dba76a2132303952024-04-16 6:48:5749 secs ago Aerodrome: RouterWrapped Ether0.034 ETH
0x9c4e68641f369dde8a42152a21df5356a02f2a15a0e21f8217df34824ab51fde132303952024-04-16 6:48:5749 secs ago Aerodrome: Router0x873ad68712498b2430906baa29c90b4d492511c70.019832976026962211 ETH
0x9c4e68641f369dde8a42152a21df5356a02f2a15a0e21f8217df34824ab51fde132303952024-04-16 6:48:5749 secs ago Wrapped Ether Aerodrome: Router0.019832976026962211 ETH
0xb9294f7acac602253338d82ca2ac2c28bfb86a49471aa72df528d6c2aac3c308132303932024-04-16 6:48:5353 secs ago Aerodrome: RouterWrapped Ether0.1 ETH
0x15e59aae421cead4aa754079254bc3719b3c639ec6459d8b3c64e802b609b08f132303872024-04-16 6:48:411 min ago Aerodrome: Router0xe99d9cb3afd16ee9385af0d2eb57a79927b4b6930.012934724904584677 ETH
0x15e59aae421cead4aa754079254bc3719b3c639ec6459d8b3c64e802b609b08f132303872024-04-16 6:48:411 min ago Wrapped Ether Aerodrome: Router0.012934724904584677 ETH
0xec9f7dddf3376e4308a2f59d8d51ca20d585cea33d562cc9e93898a8349b0318132303812024-04-16 6:48:291 min ago Aerodrome: RouterWrapped Ether0.29 ETH
0x5031c8a399cd945aa8fcaeec4cb69915c5951eade7f0f6e69e3c5d227690d2b8132303742024-04-16 6:48:151 min ago Aerodrome: Router0x87c7b23d5726b4d26601669582c00f0e4d2a51c10.001228942726305286 ETH
0x5031c8a399cd945aa8fcaeec4cb69915c5951eade7f0f6e69e3c5d227690d2b8132303742024-04-16 6:48:151 min ago Wrapped Ether Aerodrome: Router0.001228942726305286 ETH
0x66355de0e39b8ac3ba13b1f2b4c9b0337289fdce0197dbae1302aed118031709132303582024-04-16 6:47:432 mins ago Aerodrome: RouterWrapped Ether0.000395317424009015 ETH
0x5491bd7cd489ee9f2a1c0a8133bd5d6a55d13083e5754e605f4af7b38db56df1132303512024-04-16 6:47:292 mins ago Aerodrome: RouterWrapped Ether0.000563946 ETH
0x45531828dfaa32cbd2030246a0b2d6bd358f0dbae72c192bbbc0c1ee15eeeaa5132303502024-04-16 6:47:272 mins ago Aerodrome: RouterWrapped Ether0.001 ETH
0x4d27b5809a5dc3de09fc16abf9bceeb37314f2acd75652f52b09b043170ddf2c132303362024-04-16 6:46:592 mins ago Aerodrome: Router0x90e7a274cdb155b3cae35b1d073bfc59d2cac3050.000024038936847157 ETH
0x4d27b5809a5dc3de09fc16abf9bceeb37314f2acd75652f52b09b043170ddf2c132303362024-04-16 6:46:592 mins ago Wrapped Ether Aerodrome: Router0.000024038936847157 ETH
0x3829f0407e2d02a77c448b4763b820857ddb4250489a4205b2681b9fc7b18161132303342024-04-16 6:46:552 mins ago Aerodrome: Router0x8dcb640e52a9556de2f1be9656792698b859e6160.325058327358044995 ETH
0x3829f0407e2d02a77c448b4763b820857ddb4250489a4205b2681b9fc7b18161132303342024-04-16 6:46:552 mins ago Wrapped Ether Aerodrome: Router0.325058327358044995 ETH
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Router

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSL 1.1 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at basescan.org on 2023-08-28
*/

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

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

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

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

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

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

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

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

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

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

interface IPool {
    error DepositsNotEqual();
    error BelowMinimumK();
    error FactoryAlreadySet();
    error InsufficientLiquidity();
    error InsufficientLiquidityMinted();
    error InsufficientLiquidityBurned();
    error InsufficientOutputAmount();
    error InsufficientInputAmount();
    error IsPaused();
    error InvalidTo();
    error K();
    error NotEmergencyCouncil();

    event Fees(address indexed sender, uint256 amount0, uint256 amount1);
    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, address indexed to, uint256 amount0, uint256 amount1);
    event Swap(
        address indexed sender,
        address indexed to,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out
    );
    event Sync(uint256 reserve0, uint256 reserve1);
    event Claim(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1);

    // Struct to capture time period obervations every 30 minutes, used for local oracles
    struct Observation {
        uint256 timestamp;
        uint256 reserve0Cumulative;
        uint256 reserve1Cumulative;
    }

    /// @notice Returns the decimal (dec), reserves (r), stable (st), and tokens (t) of token0 and token1
    function metadata()
        external
        view
        returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1);

    /// @notice Claim accumulated but unclaimed fees (claimable0 and claimable1)
    function claimFees() external returns (uint256, uint256);

    /// @notice Returns [token0, token1]
    function tokens() external view returns (address, address);

    /// @notice Address of token in the pool with the lower address value
    function token0() external view returns (address);

    /// @notice Address of token in the poool with the higher address value
    function token1() external view returns (address);

    /// @notice Address of linked PoolFees.sol
    function poolFees() external view returns (address);

    /// @notice Address of PoolFactory that created this contract
    function factory() external view returns (address);

    /// @notice Capture oracle reading every 30 minutes (1800 seconds)
    function periodSize() external view returns (uint256);

    /// @notice Amount of token0 in pool
    function reserve0() external view returns (uint256);

    /// @notice Amount of token1 in pool
    function reserve1() external view returns (uint256);

    /// @notice Timestamp of last update to pool
    function blockTimestampLast() external view returns (uint256);

    /// @notice Cumulative of reserve0 factoring in time elapsed
    function reserve0CumulativeLast() external view returns (uint256);

    /// @notice Cumulative of reserve1 factoring in time elapsed
    function reserve1CumulativeLast() external view returns (uint256);

    /// @notice Accumulated fees of token0 (global)
    function index0() external view returns (uint256);

    /// @notice Accumulated fees of token1 (global)
    function index1() external view returns (uint256);

    /// @notice Get an LP's relative index0 to index0
    function supplyIndex0(address) external view returns (uint256);

    /// @notice Get an LP's relative index1 to index1
    function supplyIndex1(address) external view returns (uint256);

    /// @notice Amount of unclaimed, but claimable tokens from fees of token0 for an LP
    function claimable0(address) external view returns (uint256);

    /// @notice Amount of unclaimed, but claimable tokens from fees of token1 for an LP
    function claimable1(address) external view returns (uint256);

    /// @notice Returns the value of K in the Pool, based on its reserves.
    function getK() external returns (uint256);

    /// @notice Set pool name
    ///         Only callable by Voter.emergencyCouncil()
    /// @param __name String of new name
    function setName(string calldata __name) external;

    /// @notice Set pool symbol
    ///         Only callable by Voter.emergencyCouncil()
    /// @param __symbol String of new symbol
    function setSymbol(string calldata __symbol) external;

    /// @notice Get the number of observations recorded
    function observationLength() external view returns (uint256);

    /// @notice Get the value of the most recent observation
    function lastObservation() external view returns (Observation memory);

    /// @notice True if pool is stable, false if volatile
    function stable() external view returns (bool);

    /// @notice Produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
    function currentCumulativePrices()
        external
        view
        returns (uint256 reserve0Cumulative, uint256 reserve1Cumulative, uint256 blockTimestamp);

    /// @notice Provides twap price with user configured granularity, up to the full window size
    /// @param tokenIn .
    /// @param amountIn .
    /// @param granularity .
    /// @return amountOut .
    function quote(address tokenIn, uint256 amountIn, uint256 granularity) external view returns (uint256 amountOut);

    /// @notice Returns a memory set of TWAP prices
    ///         Same as calling sample(tokenIn, amountIn, points, 1)
    /// @param tokenIn .
    /// @param amountIn .
    /// @param points Number of points to return
    /// @return Array of TWAP prices
    function prices(address tokenIn, uint256 amountIn, uint256 points) external view returns (uint256[] memory);

    /// @notice Same as prices with with an additional window argument.
    ///         Window = 2 means 2 * 30min (or 1 hr) between observations
    /// @param tokenIn .
    /// @param amountIn .
    /// @param points .
    /// @param window .
    /// @return Array of TWAP prices
    function sample(
        address tokenIn,
        uint256 amountIn,
        uint256 points,
        uint256 window
    ) external view returns (uint256[] memory);

    /// @notice This low-level function should be called from a contract which performs important safety checks
    /// @param amount0Out   Amount of token0 to send to `to`
    /// @param amount1Out   Amount of token1 to send to `to`
    /// @param to           Address to recieve the swapped output
    /// @param data         Additional calldata for flashloans
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;

    /// @notice This low-level function should be called from a contract which performs important safety checks
    ///         standard uniswap v2 implementation
    /// @param to Address to receive token0 and token1 from burning the pool token
    /// @return amount0 Amount of token0 returned
    /// @return amount1 Amount of token1 returned
    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    /// @notice This low-level function should be called by addLiquidity functions in Router.sol, which performs important safety checks
    ///         standard uniswap v2 implementation
    /// @param to           Address to receive the minted LP token
    /// @return liquidity   Amount of LP token minted
    function mint(address to) external returns (uint256 liquidity);

    /// @notice Update reserves and, on the first call per block, price accumulators
    /// @return _reserve0 .
    /// @return _reserve1 .
    /// @return _blockTimestampLast .
    function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast);

    /// @notice Get the amount of tokenOut given the amount of tokenIn
    /// @param amountIn Amount of token in
    /// @param tokenIn  Address of token
    /// @return Amount out
    function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256);

    /// @notice Force balances to match reserves
    /// @param to Address to receive any skimmed rewards
    function skim(address to) external;

    /// @notice Force reserves to match balances
    function sync() external;

    /// @notice Called on pool creation by PoolFactory
    /// @param _token0 Address of token0
    /// @param _token1 Address of token1
    /// @param _stable True if stable, false if volatile
    function initialize(address _token0, address _token1, bool _stable) external;
}

interface IPoolFactory {
    event SetFeeManager(address feeManager);
    event SetPauser(address pauser);
    event SetPauseState(bool state);
    event SetVoter(address voter);
    event PoolCreated(address indexed token0, address indexed token1, bool indexed stable, address pool, uint256);
    event SetCustomFee(address indexed pool, uint256 fee);

    error FeeInvalid();
    error FeeTooHigh();
    error InvalidPool();
    error NotFeeManager();
    error NotPauser();
    error NotVoter();
    error PoolAlreadyExists();
    error SameAddress();
    error ZeroFee();
    error ZeroAddress();

    /// @notice returns the number of pools created from this factory
    function allPoolsLength() external view returns (uint256);

    /// @notice Is a valid pool created by this factory.
    /// @param .
    function isPool(address pool) external view returns (bool);

    /// @notice Return address of pool created by this factory
    /// @param tokenA .
    /// @param tokenB .
    /// @param stable True if stable, false if volatile
    function getPool(address tokenA, address tokenB, bool stable) external view returns (address);

    /// @notice Support for v3-style pools which wraps around getPool(tokenA,tokenB,stable)
    /// @dev fee is converted to stable boolean.
    /// @param tokenA .
    /// @param tokenB .
    /// @param fee  1 if stable, 0 if volatile, else returns address(0)
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address);

    /// @dev Only called once to set to Voter.sol - Voter does not have a function
    ///      to call this contract method, so once set it's immutable.
    ///      This also follows convention of setVoterAndDistributor() in VotingEscrow.sol
    /// @param _voter .
    function setVoter(address _voter) external;

    function setPauser(address _pauser) external;

    function setPauseState(bool _state) external;

    function setFeeManager(address _feeManager) external;

    /// @notice Set default fee for stable and volatile pools.
    /// @dev Throws if higher than maximum fee.
    ///      Throws if fee is zero.
    /// @param _stable Stable or volatile pool.
    /// @param _fee .
    function setFee(bool _stable, uint256 _fee) external;

    /// @notice Set overriding fee for a pool from the default
    /// @dev A custom fee of zero means the default fee will be used.
    function setCustomFee(address _pool, uint256 _fee) external;

    /// @notice Returns fee for a pool, as custom fees are possible.
    function getFee(address _pool, bool _stable) external view returns (uint256);

    /// @notice Create a pool given two tokens and if they're stable/volatile
    /// @dev token order does not matter
    /// @param tokenA .
    /// @param tokenB .
    /// @param stable .
    function createPool(address tokenA, address tokenB, bool stable) external returns (address pool);

    /// @notice Support for v3-style pools which wraps around createPool(tokena,tokenB,stable)
    /// @dev fee is converted to stable boolean
    /// @dev token order does not matter
    /// @param tokenA .
    /// @param tokenB .
    /// @param fee 1 if stable, 0 if volatile, else revert
    function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool);

    function isPaused() external view returns (bool);

    function voter() external view returns (address);

    function implementation() external view returns (address);
}

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

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256) external;
}

interface IRouter {
    struct Route {
        address from;
        address to;
        bool stable;
        address factory;
    }

    error ETHTransferFailed();
    error Expired();
    error InsufficientAmount();
    error InsufficientAmountA();
    error InsufficientAmountB();
    error InsufficientAmountADesired();
    error InsufficientAmountBDesired();
    error InsufficientAmountAOptimal();
    error InsufficientLiquidity();
    error InsufficientOutputAmount();
    error InvalidAmountInForETHDeposit();
    error InvalidTokenInForETHDeposit();
    error InvalidPath();
    error InvalidRouteA();
    error InvalidRouteB();
    error OnlyWETH();
    error PoolDoesNotExist();
    error PoolFactoryDoesNotExist();
    error SameAddresses();
    error ZeroAddress();

    /// @notice Address of FactoryRegistry.sol
    function factoryRegistry() external view returns (address);

    /// @notice Address of Protocol PoolFactory.sol
    function defaultFactory() external view returns (address);

    /// @notice Address of Voter.sol
    function voter() external view returns (address);

    /// @notice Interface of WETH contract used for WETH => ETH wrapping/unwrapping
    function weth() external view returns (IWETH);

    /// @dev Represents Ether. Used by zapper to determine whether to return assets as ETH/WETH.
    function ETHER() external view returns (address);

    /// @dev Struct containing information necessary to zap in and out of pools
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           Stable or volatile pool
    /// @param factory          factory of pool
    /// @param amountOutMinA    Minimum amount expected from swap leg of zap via routesA
    /// @param amountOutMinB    Minimum amount expected from swap leg of zap via routesB
    /// @param amountAMin       Minimum amount of tokenA expected from liquidity leg of zap
    /// @param amountBMin       Minimum amount of tokenB expected from liquidity leg of zap
    struct Zap {
        address tokenA;
        address tokenB;
        bool stable;
        address factory;
        uint256 amountOutMinA;
        uint256 amountOutMinB;
        uint256 amountAMin;
        uint256 amountBMin;
    }

    /// @notice Sort two tokens by which address value is less than the other
    /// @param tokenA   Address of token to sort
    /// @param tokenB   Address of token to sort
    /// @return token0  Lower address value between tokenA and tokenB
    /// @return token1  Higher address value between tokenA and tokenB
    function sortTokens(address tokenA, address tokenB) external pure returns (address token0, address token1);

    /// @notice Calculate the address of a pool by its' factory.
    ///         Used by all Router functions containing a `Route[]` or `_factory` argument.
    ///         Reverts if _factory is not approved by the FactoryRegistry
    /// @dev Returns a randomly generated address for a nonexistent pool
    /// @param tokenA   Address of token to query
    /// @param tokenB   Address of token to query
    /// @param stable   True if pool is stable, false if volatile
    /// @param _factory Address of factory which created the pool
    function poolFor(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory
    ) external view returns (address pool);

    /// @notice Fetch and sort the reserves for a pool
    /// @param tokenA       .
    /// @param tokenB       .
    /// @param stable       True if pool is stable, false if volatile
    /// @param _factory     Address of PoolFactory for tokenA and tokenB
    /// @return reserveA    Amount of reserves of the sorted token A
    /// @return reserveB    Amount of reserves of the sorted token B
    function getReserves(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory
    ) external view returns (uint256 reserveA, uint256 reserveB);

    /// @notice Perform chained getAmountOut calculations on any number of pools
    function getAmountsOut(uint256 amountIn, Route[] memory routes) external view returns (uint256[] memory amounts);

    // **** ADD LIQUIDITY ****

    /// @notice Quote the amount deposited into a Pool
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           True if pool is stable, false if volatile
    /// @param _factory         Address of PoolFactory for tokenA and tokenB
    /// @param amountADesired   Amount of tokenA desired to deposit
    /// @param amountBDesired   Amount of tokenB desired to deposit
    /// @return amountA         Amount of tokenA to actually deposit
    /// @return amountB         Amount of tokenB to actually deposit
    /// @return liquidity       Amount of liquidity token returned from deposit
    function quoteAddLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 amountADesired,
        uint256 amountBDesired
    ) external view returns (uint256 amountA, uint256 amountB, uint256 liquidity);

    /// @notice Quote the amount of liquidity removed from a Pool
    /// @param tokenA       .
    /// @param tokenB       .
    /// @param stable       True if pool is stable, false if volatile
    /// @param _factory     Address of PoolFactory for tokenA and tokenB
    /// @param liquidity    Amount of liquidity to remove
    /// @return amountA     Amount of tokenA received
    /// @return amountB     Amount of tokenB received
    function quoteRemoveLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 liquidity
    ) external view returns (uint256 amountA, uint256 amountB);

    /// @notice Add liquidity of two tokens to a Pool
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           True if pool is stable, false if volatile
    /// @param amountADesired   Amount of tokenA desired to deposit
    /// @param amountBDesired   Amount of tokenB desired to deposit
    /// @param amountAMin       Minimum amount of tokenA to deposit
    /// @param amountBMin       Minimum amount of tokenB to deposit
    /// @param to               Recipient of liquidity token
    /// @param deadline         Deadline to receive liquidity
    /// @return amountA         Amount of tokenA to actually deposit
    /// @return amountB         Amount of tokenB to actually deposit
    /// @return liquidity       Amount of liquidity token returned from deposit
    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);

    /// @notice Add liquidity of a token and WETH (transferred as ETH) to a Pool
    /// @param token                .
    /// @param stable               True if pool is stable, false if volatile
    /// @param amountTokenDesired   Amount of token desired to deposit
    /// @param amountTokenMin       Minimum amount of token to deposit
    /// @param amountETHMin         Minimum amount of ETH to deposit
    /// @param to                   Recipient of liquidity token
    /// @param deadline             Deadline to add liquidity
    /// @return amountToken         Amount of token to actually deposit
    /// @return amountETH           Amount of tokenETH to actually deposit
    /// @return liquidity           Amount of liquidity token returned from deposit
    function addLiquidityETH(
        address token,
        bool stable,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);

    // **** REMOVE LIQUIDITY ****

    /// @notice Remove liquidity of two tokens from a Pool
    /// @param tokenA       .
    /// @param tokenB       .
    /// @param stable       True if pool is stable, false if volatile
    /// @param liquidity    Amount of liquidity to remove
    /// @param amountAMin   Minimum amount of tokenA to receive
    /// @param amountBMin   Minimum amount of tokenB to receive
    /// @param to           Recipient of tokens received
    /// @param deadline     Deadline to remove liquidity
    /// @return amountA     Amount of tokenA received
    /// @return amountB     Amount of tokenB received
    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    /// @notice Remove liquidity of a token and WETH (returned as ETH) from a Pool
    /// @param token            .
    /// @param stable           True if pool is stable, false if volatile
    /// @param liquidity        Amount of liquidity to remove
    /// @param amountTokenMin   Minimum amount of token to receive
    /// @param amountETHMin     Minimum amount of ETH to receive
    /// @param to               Recipient of liquidity token
    /// @param deadline         Deadline to receive liquidity
    /// @return amountToken     Amount of token received
    /// @return amountETH       Amount of ETH received
    function removeLiquidityETH(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    /// @notice Remove liquidity of a fee-on-transfer token and WETH (returned as ETH) from a Pool
    /// @param token            .
    /// @param stable           True if pool is stable, false if volatile
    /// @param liquidity        Amount of liquidity to remove
    /// @param amountTokenMin   Minimum amount of token to receive
    /// @param amountETHMin     Minimum amount of ETH to receive
    /// @param to               Recipient of liquidity token
    /// @param deadline         Deadline to receive liquidity
    /// @return amountETH       Amount of ETH received
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

    // **** SWAP ****

    /// @notice Swap one token for another
    /// @param amountIn     Amount of token in
    /// @param amountOutMin Minimum amount of desired token received
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    /// @return amounts     Array of amounts returned per route
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    /// @notice Swap ETH for a token
    /// @param amountOutMin Minimum amount of desired token received
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    /// @return amounts     Array of amounts returned per route
    function swapExactETHForTokens(
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    /// @notice Swap a token for WETH (returned as ETH)
    /// @param amountIn     Amount of token in
    /// @param amountOutMin Minimum amount of desired ETH
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    /// @return amounts     Array of amounts returned per route
    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    /// @notice Swap one token for another without slippage protection
    /// @return amounts     Array of amounts to swap  per route
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    function UNSAFE_swapExactTokensForTokens(
        uint256[] memory amounts,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory);

    // **** SWAP (supporting fee-on-transfer tokens) ****

    /// @notice Swap one token for another supporting fee-on-transfer tokens
    /// @param amountIn     Amount of token in
    /// @param amountOutMin Minimum amount of desired token received
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external;

    /// @notice Swap ETH for a token supporting fee-on-transfer tokens
    /// @param amountOutMin Minimum amount of desired token received
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external payable;

    /// @notice Swap a token for WETH (returned as ETH) supporting fee-on-transfer tokens
    /// @param amountIn     Amount of token in
    /// @param amountOutMin Minimum amount of desired ETH
    /// @param routes       Array of trade routes used in the swap
    /// @param to           Recipient of the tokens received
    /// @param deadline     Deadline to receive tokens
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external;

    /// @notice Zap a token A into a pool (B, C). (A can be equal to B or C).
    ///         Supports standard ERC20 tokens only (i.e. not fee-on-transfer tokens etc).
    ///         Slippage is required for the initial swap.
    ///         Additional slippage may be required when adding liquidity as the
    ///         price of the token may have changed.
    /// @param tokenIn      Token you are zapping in from (i.e. input token).
    /// @param amountInA    Amount of input token you wish to send down routesA
    /// @param amountInB    Amount of input token you wish to send down routesB
    /// @param zapInPool    Contains zap struct information. See Zap struct.
    /// @param routesA      Route used to convert input token to tokenA
    /// @param routesB      Route used to convert input token to tokenB
    /// @param to           Address you wish to mint liquidity to.
    /// @param stake        Auto-stake liquidity in corresponding gauge.
    /// @return liquidity   Amount of LP tokens created from zapping in.
    function zapIn(
        address tokenIn,
        uint256 amountInA,
        uint256 amountInB,
        Zap calldata zapInPool,
        Route[] calldata routesA,
        Route[] calldata routesB,
        address to,
        bool stake
    ) external payable returns (uint256 liquidity);

    /// @notice Zap out a pool (B, C) into A.
    ///         Supports standard ERC20 tokens only (i.e. not fee-on-transfer tokens etc).
    ///         Slippage is required for the removal of liquidity.
    ///         Additional slippage may be required on the swap as the
    ///         price of the token may have changed.
    /// @param tokenOut     Token you are zapping out to (i.e. output token).
    /// @param liquidity    Amount of liquidity you wish to remove.
    /// @param zapOutPool   Contains zap struct information. See Zap struct.
    /// @param routesA      Route used to convert tokenA into output token.
    /// @param routesB      Route used to convert tokenB into output token.
    function zapOut(
        address tokenOut,
        uint256 liquidity,
        Zap calldata zapOutPool,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) external;

    /// @notice Used to generate params required for zapping in.
    ///         Zap in => remove liquidity then swap.
    ///         Apply slippage to expected swap values to account for changes in reserves in between.
    /// @dev Output token refers to the token you want to zap in from.
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           .
    /// @param _factory         .
    /// @param amountInA        Amount of input token you wish to send down routesA
    /// @param amountInB        Amount of input token you wish to send down routesB
    /// @param routesA          Route used to convert input token to tokenA
    /// @param routesB          Route used to convert input token to tokenB
    /// @return amountOutMinA   Minimum output expected from swapping input token to tokenA.
    /// @return amountOutMinB   Minimum output expected from swapping input token to tokenB.
    /// @return amountAMin      Minimum amount of tokenA expected from depositing liquidity.
    /// @return amountBMin      Minimum amount of tokenB expected from depositing liquidity.
    function generateZapInParams(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 amountInA,
        uint256 amountInB,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin);

    /// @notice Used to generate params required for zapping out.
    ///         Zap out => swap then add liquidity.
    ///         Apply slippage to expected liquidity values to account for changes in reserves in between.
    /// @dev Output token refers to the token you want to zap out of.
    /// @param tokenA           .
    /// @param tokenB           .
    /// @param stable           .
    /// @param _factory         .
    /// @param liquidity        Amount of liquidity being zapped out of into a given output token.
    /// @param routesA          Route used to convert tokenA into output token.
    /// @param routesB          Route used to convert tokenB into output token.
    /// @return amountOutMinA   Minimum output expected from swapping tokenA into output token.
    /// @return amountOutMinB   Minimum output expected from swapping tokenB into output token.
    /// @return amountAMin      Minimum amount of tokenA expected from withdrawing liquidity.
    /// @return amountBMin      Minimum amount of tokenB expected from withdrawing liquidity.
    function generateZapOutParams(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 liquidity,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin);

    /// @notice Used by zapper to determine appropriate ratio of A to B to deposit liquidity. Assumes stable pool.
    /// @dev Returns stable liquidity ratio of B to (A + B).
    ///      E.g. if ratio is 0.4, it means there is more of A than there is of B.
    ///      Therefore you should deposit more of token A than B.
    /// @param tokenA   tokenA of stable pool you are zapping into.
    /// @param tokenB   tokenB of stable pool you are zapping into.
    /// @param factory  Factory that created stable pool.
    /// @return ratio   Ratio of token0 to token1 required to deposit into zap.
    function quoteStableLiquidityRatio(
        address tokenA,
        address tokenB,
        address factory
    ) external view returns (uint256 ratio);
}

interface IVoter {
    error AlreadyVotedOrDeposited();
    error DistributeWindow();
    error FactoryPathNotApproved();
    error GaugeAlreadyKilled();
    error GaugeAlreadyRevived();
    error GaugeExists();
    error GaugeDoesNotExist(address _pool);
    error GaugeNotAlive(address _gauge);
    error InactiveManagedNFT();
    error MaximumVotingNumberTooLow();
    error NonZeroVotes();
    error NotAPool();
    error NotApprovedOrOwner();
    error NotGovernor();
    error NotEmergencyCouncil();
    error NotMinter();
    error NotWhitelistedNFT();
    error NotWhitelistedToken();
    error SameValue();
    error SpecialVotingWindow();
    error TooManyPools();
    error UnequalLengths();
    error ZeroBalance();
    error ZeroAddress();

    event GaugeCreated(
        address indexed poolFactory,
        address indexed votingRewardsFactory,
        address indexed gaugeFactory,
        address pool,
        address bribeVotingReward,
        address feeVotingReward,
        address gauge,
        address creator
    );
    event GaugeKilled(address indexed gauge);
    event GaugeRevived(address indexed gauge);
    event Voted(
        address indexed voter,
        address indexed pool,
        uint256 indexed tokenId,
        uint256 weight,
        uint256 totalWeight,
        uint256 timestamp
    );
    event Abstained(
        address indexed voter,
        address indexed pool,
        uint256 indexed tokenId,
        uint256 weight,
        uint256 totalWeight,
        uint256 timestamp
    );
    event NotifyReward(address indexed sender, address indexed reward, uint256 amount);
    event DistributeReward(address indexed sender, address indexed gauge, uint256 amount);
    event WhitelistToken(address indexed whitelister, address indexed token, bool indexed _bool);
    event WhitelistNFT(address indexed whitelister, uint256 indexed tokenId, bool indexed _bool);

    /// @notice Store trusted forwarder address to pass into factories
    function forwarder() external view returns (address);

    /// @notice The ve token that governs these contracts
    function ve() external view returns (address);

    /// @notice Factory registry for valid pool / gauge / rewards factories
    function factoryRegistry() external view returns (address);

    /// @notice Address of Minter.sol
    function minter() external view returns (address);

    /// @notice Standard OZ IGovernor using ve for vote weights.
    function governor() external view returns (address);

    /// @notice Custom Epoch Governor using ve for vote weights.
    function epochGovernor() external view returns (address);

    /// @notice credibly neutral party similar to Curve's Emergency DAO
    function emergencyCouncil() external view returns (address);

    /// @dev Total Voting Weights
    function totalWeight() external view returns (uint256);

    /// @dev Most number of pools one voter can vote for at once
    function maxVotingNum() external view returns (uint256);

    // mappings
    /// @dev Pool => Gauge
    function gauges(address pool) external view returns (address);

    /// @dev Gauge => Pool
    function poolForGauge(address gauge) external view returns (address);

    /// @dev Gauge => Fees Voting Reward
    function gaugeToFees(address gauge) external view returns (address);

    /// @dev Gauge => Bribes Voting Reward
    function gaugeToBribe(address gauge) external view returns (address);

    /// @dev Pool => Weights
    function weights(address pool) external view returns (uint256);

    /// @dev NFT => Pool => Votes
    function votes(uint256 tokenId, address pool) external view returns (uint256);

    /// @dev NFT => Total voting weight of NFT
    function usedWeights(uint256 tokenId) external view returns (uint256);

    /// @dev Nft => Timestamp of last vote (ensures single vote per epoch)
    function lastVoted(uint256 tokenId) external view returns (uint256);

    /// @dev Address => Gauge
    function isGauge(address) external view returns (bool);

    /// @dev Token => Whitelisted status
    function isWhitelistedToken(address token) external view returns (bool);

    /// @dev TokenId => Whitelisted status
    function isWhitelistedNFT(uint256 tokenId) external view returns (bool);

    /// @dev Gauge => Liveness status
    function isAlive(address gauge) external view returns (bool);

    /// @dev Gauge => Amount claimable
    function claimable(address gauge) external view returns (uint256);

    /// @notice Number of pools with a Gauge
    function length() external view returns (uint256);

    /// @notice Called by Minter to distribute weekly emissions rewards for disbursement amongst gauges.
    /// @dev Assumes totalWeight != 0 (Will never be zero as long as users are voting).
    ///      Throws if not called by minter.
    /// @param _amount Amount of rewards to distribute.
    function notifyRewardAmount(uint256 _amount) external;

    /// @dev Utility to distribute to gauges of pools in range _start to _finish.
    /// @param _start   Starting index of gauges to distribute to.
    /// @param _finish  Ending index of gauges to distribute to.
    function distribute(uint256 _start, uint256 _finish) external;

    /// @dev Utility to distribute to gauges of pools in array.
    /// @param _gauges Array of gauges to distribute to.
    function distribute(address[] memory _gauges) external;

    /// @notice Called by users to update voting balances in voting rewards contracts.
    /// @param _tokenId Id of veNFT whose balance you wish to update.
    function poke(uint256 _tokenId) external;

    /// @notice Called by users to vote for pools. Votes distributed proportionally based on weights.
    ///         Can only vote or deposit into a managed NFT once per epoch.
    ///         Can only vote for gauges that have not been killed.
    /// @dev Weights are distributed proportional to the sum of the weights in the array.
    ///      Throws if length of _poolVote and _weights do not match.
    /// @param _tokenId     Id of veNFT you are voting with.
    /// @param _poolVote    Array of pools you are voting for.
    /// @param _weights     Weights of pools.
    function vote(uint256 _tokenId, address[] calldata _poolVote, uint256[] calldata _weights) external;

    /// @notice Called by users to reset voting state. Required if you wish to make changes to
    ///         veNFT state (e.g. merge, split, deposit into managed etc).
    ///         Cannot reset in the same epoch that you voted in.
    ///         Can vote or deposit into a managed NFT again after reset.
    /// @param _tokenId Id of veNFT you are reseting.
    function reset(uint256 _tokenId) external;

    /// @notice Called by users to deposit into a managed NFT.
    ///         Can only vote or deposit into a managed NFT once per epoch.
    ///         Note that NFTs deposited into a managed NFT will be re-locked
    ///         to the maximum lock time on withdrawal.
    /// @dev Throws if not approved or owner.
    ///      Throws if managed NFT is inactive.
    ///      Throws if depositing within privileged window (one hour prior to epoch flip).
    function depositManaged(uint256 _tokenId, uint256 _mTokenId) external;

    /// @notice Called by users to withdraw from a managed NFT.
    ///         Cannot do it in the same epoch that you deposited into a managed NFT.
    ///         Can vote or deposit into a managed NFT again after withdrawing.
    ///         Note that the NFT withdrawn is re-locked to the maximum lock time.
    function withdrawManaged(uint256 _tokenId) external;

    /// @notice Claim emissions from gauges.
    /// @param _gauges Array of gauges to collect emissions from.
    function claimRewards(address[] memory _gauges) external;

    /// @notice Claim bribes for a given NFT.
    /// @dev Utility to help batch bribe claims.
    /// @param _bribes  Array of BribeVotingReward contracts to collect from.
    /// @param _tokens  Array of tokens that are used as bribes.
    /// @param _tokenId Id of veNFT that you wish to claim bribes for.
    function claimBribes(address[] memory _bribes, address[][] memory _tokens, uint256 _tokenId) external;

    /// @notice Claim fees for a given NFT.
    /// @dev Utility to help batch fee claims.
    /// @param _fees    Array of FeesVotingReward contracts to collect from.
    /// @param _tokens  Array of tokens that are used as fees.
    /// @param _tokenId Id of veNFT that you wish to claim fees for.
    function claimFees(address[] memory _fees, address[][] memory _tokens, uint256 _tokenId) external;

    /// @notice Set new governor.
    /// @dev Throws if not called by governor.
    /// @param _governor .
    function setGovernor(address _governor) external;

    /// @notice Set new epoch based governor.
    /// @dev Throws if not called by governor.
    /// @param _epochGovernor .
    function setEpochGovernor(address _epochGovernor) external;

    /// @notice Set new emergency council.
    /// @dev Throws if not called by emergency council.
    /// @param _emergencyCouncil .
    function setEmergencyCouncil(address _emergencyCouncil) external;

    /// @notice Set maximum number of gauges that can be voted for.
    /// @dev Throws if not called by governor.
    ///      Throws if _maxVotingNum is too low.
    ///      Throws if the values are the same.
    /// @param _maxVotingNum .
    function setMaxVotingNum(uint256 _maxVotingNum) external;

    /// @notice Whitelist (or unwhitelist) token for use in bribes.
    /// @dev Throws if not called by governor.
    /// @param _token .
    /// @param _bool .
    function whitelistToken(address _token, bool _bool) external;

    /// @notice Whitelist (or unwhitelist) token id for voting in last hour prior to epoch flip.
    /// @dev Throws if not called by governor.
    ///      Throws if already whitelisted.
    /// @param _tokenId .
    /// @param _bool .
    function whitelistNFT(uint256 _tokenId, bool _bool) external;

    /// @notice Create a new gauge (unpermissioned).
    /// @dev Governor can create a new gauge for a pool with any address.
    /// @param _poolFactory .
    /// @param _pool .
    function createGauge(address _poolFactory, address _pool) external returns (address);

    /// @notice Kills a gauge. The gauge will not receive any new emissions and cannot be deposited into.
    ///         Can still withdraw from gauge.
    /// @dev Throws if not called by emergency council.
    ///      Throws if gauge already killed.
    /// @param _gauge .
    function killGauge(address _gauge) external;

    /// @notice Revives a killed gauge. Gauge will can receive emissions and deposits again.
    /// @dev Throws if not called by emergency council.
    ///      Throws if gauge is not killed.
    /// @param _gauge .
    function reviveGauge(address _gauge) external;

    /// @dev Update claims to emissions for an array of gauges.
    /// @param _gauges Array of gauges to update emissions for.
    function updateFor(address[] memory _gauges) external;

    /// @dev Update claims to emissions for gauges based on their pool id as stored in Voter.
    /// @param _start   Starting index of pools.
    /// @param _end     Ending index of pools.
    function updateFor(uint256 _start, uint256 _end) external;

    /// @dev Update claims to emissions for single gauge
    /// @param _gauge .
    function updateFor(address _gauge) external;
}

interface IGauge {
    error NotAlive();
    error NotAuthorized();
    error NotVoter();
    error NotTeam();
    error RewardRateTooHigh();
    error ZeroAmount();
    error ZeroRewardRate();

    event Deposit(address indexed from, address indexed to, uint256 amount);
    event Withdraw(address indexed from, uint256 amount);
    event NotifyReward(address indexed from, uint256 amount);
    event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1);
    event ClaimRewards(address indexed from, uint256 amount);

    /// @notice Address of the pool LP token which is deposited (staked) for rewards
    function stakingToken() external view returns (address);

    /// @notice Address of the token (AERO) rewarded to stakers
    function rewardToken() external view returns (address);

    /// @notice Address of the FeesVotingReward contract linked to the gauge
    function feesVotingReward() external view returns (address);

    /// @notice Address of Protocol Voter
    function voter() external view returns (address);

    /// @notice Address of Protocol Voting Escrow
    function ve() external view returns (address);

    /// @notice Returns if gauge is linked to a legitimate Protocol pool
    function isPool() external view returns (bool);

    /// @notice Timestamp end of current rewards period
    function periodFinish() external view returns (uint256);

    /// @notice Current reward rate of rewardToken to distribute per second
    function rewardRate() external view returns (uint256);

    /// @notice Most recent timestamp contract has updated state
    function lastUpdateTime() external view returns (uint256);

    /// @notice Most recent stored value of rewardPerToken
    function rewardPerTokenStored() external view returns (uint256);

    /// @notice Amount of stakingToken deposited for rewards
    function totalSupply() external view returns (uint256);

    /// @notice Get the amount of stakingToken deposited by an account
    function balanceOf(address) external view returns (uint256);

    /// @notice Cached rewardPerTokenStored for an account based on their most recent action
    function userRewardPerTokenPaid(address) external view returns (uint256);

    /// @notice Cached amount of rewardToken earned for an account
    function rewards(address) external view returns (uint256);

    /// @notice View to see the rewardRate given the timestamp of the start of the epoch
    function rewardRateByEpoch(uint256) external view returns (uint256);

    /// @notice Cached amount of fees generated from the Pool linked to the Gauge of token0
    function fees0() external view returns (uint256);

    /// @notice Cached amount of fees generated from the Pool linked to the Gauge of token1
    function fees1() external view returns (uint256);

    /// @notice Get the current reward rate per unit of stakingToken deposited
    function rewardPerToken() external view returns (uint256 _rewardPerToken);

    /// @notice Returns the last time the reward was modified or periodFinish if the reward has ended
    function lastTimeRewardApplicable() external view returns (uint256 _time);

    /// @notice Returns accrued balance to date from last claim / first deposit.
    function earned(address _account) external view returns (uint256 _earned);

    /// @notice Total amount of rewardToken to distribute for the current rewards period
    function left() external view returns (uint256 _left);

    /// @notice Retrieve rewards for an address.
    /// @dev Throws if not called by same address or voter.
    /// @param _account .
    function getReward(address _account) external;

    /// @notice Deposit LP tokens into gauge for msg.sender
    /// @param _amount .
    function deposit(uint256 _amount) external;

    /// @notice Deposit LP tokens into gauge for any user
    /// @param _amount .
    /// @param _recipient Recipient to give balance to
    function deposit(uint256 _amount, address _recipient) external;

    /// @notice Withdraw LP tokens for user
    /// @param _amount .
    function withdraw(uint256 _amount) external;

    /// @dev Notifies gauge of gauge rewards. Assumes gauge reward tokens is 18 decimals.
    ///      If not 18 decimals, rewardRate may have rounding issues.
    function notifyRewardAmount(uint256 amount) external;

    /// @dev Notifies gauge of gauge rewards without distributing its fees.
    ///      Assumes gauge reward tokens is 18 decimals.
    ///      If not 18 decimals, rewardRate may have rounding issues.
    function notifyRewardWithoutClaim(uint256 amount) external;
}

interface IFactoryRegistry {
    error FallbackFactory();
    error InvalidFactoriesToPoolFactory();
    error PathAlreadyApproved();
    error PathNotApproved();
    error SameAddress();
    error ZeroAddress();

    event Approve(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory);
    event Unapprove(address indexed poolFactory, address indexed votingRewardsFactory, address indexed gaugeFactory);
    event SetManagedRewardsFactory(address indexed _newRewardsFactory);

    /// @notice Approve a set of factories used in the Protocol.
    ///         Router.sol is able to swap any poolFactories currently approved.
    ///         Cannot approve address(0) factories.
    ///         Cannot aprove path that is already approved.
    ///         Each poolFactory has one unique set and maintains state.  In the case a poolFactory is unapproved
    ///             and then re-approved, the same set of factories must be used.  In other words, you cannot overwrite
    ///             the factories tied to a poolFactory address.
    ///         VotingRewardsFactories and GaugeFactories may use the same address across multiple poolFactories.
    /// @dev Callable by onlyOwner
    /// @param poolFactory .
    /// @param votingRewardsFactory .
    /// @param gaugeFactory .
    function approve(address poolFactory, address votingRewardsFactory, address gaugeFactory) external;

    /// @notice Unapprove a set of factories used in the Protocol.
    ///         While a poolFactory is unapproved, Router.sol cannot swap with pools made from the corresponding factory
    ///         Can only unapprove an approved path.
    ///         Cannot unapprove the fallback path (core v2 factories).
    /// @dev Callable by onlyOwner
    /// @param poolFactory .
    function unapprove(address poolFactory) external;

    /// @notice Factory to create free and locked rewards for a managed veNFT
    function managedRewardsFactory() external view returns (address);

    /// @notice Set the rewards factory address
    /// @dev Callable by onlyOwner
    /// @param _newManagedRewardsFactory address of new managedRewardsFactory
    function setManagedRewardsFactory(address _newManagedRewardsFactory) external;

    /// @notice Get the factories correlated to a poolFactory.
    ///         Once set, this can never be modified.
    ///         Returns the correlated factories even after an approved poolFactory is unapproved.
    function factoriesToPoolFactory(
        address poolFactory
    ) external view returns (address votingRewardsFactory, address gaugeFactory);

    /// @notice Get all PoolFactories approved by the registry
    /// @dev The same PoolFactory address cannot be used twice
    /// @return Array of PoolFactory addresses
    function poolFactories() external view returns (address[] memory);

    /// @notice Check if a PoolFactory is approved within the factory registry.  Router uses this method to
    ///         ensure a pool swapped from is approved.
    /// @param poolFactory .
    /// @return True if PoolFactory is approved, else false
    function isPoolFactoryApproved(address poolFactory) external view returns (bool);

    /// @notice Get the length of the poolFactories array
    function poolFactoriesLength() external view returns (uint256);
}

// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

/**
 * @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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

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

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

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

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

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

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

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

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

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

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

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

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

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

/**
 * @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 Context variant with ERC2771 support.
 */
abstract contract ERC2771Context is Context {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable _trustedForwarder;

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

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

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

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

// OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol)

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

/// @title Protocol Router
/// @author velodrome.finance, @pegahcarter
/// @notice Router allows routes through any pools created by any factory adhering to univ2 interface.
contract Router is IRouter, ERC2771Context {
    using SafeERC20 for IERC20;

    /// @inheritdoc IRouter
    address public immutable factoryRegistry;
    /// @inheritdoc IRouter
    address public immutable defaultFactory;
    /// @inheritdoc IRouter
    address public immutable voter;
    /// @inheritdoc IRouter
    IWETH public immutable weth;
    uint256 internal constant MINIMUM_LIQUIDITY = 10 ** 3;
    /// @inheritdoc IRouter
    address public constant ETHER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    modifier ensure(uint256 deadline) {
        _ensureDeadline(deadline);
        _;
    }

    function _ensureDeadline(uint256 deadline) internal view {
        if (deadline < block.timestamp) revert Expired();
    }

    constructor(
        address _forwarder,
        address _factoryRegistry,
        address _factory,
        address _voter,
        address _weth
    ) ERC2771Context(_forwarder) {
        factoryRegistry = _factoryRegistry;
        defaultFactory = _factory;
        voter = _voter;
        weth = IWETH(_weth);
    }

    receive() external payable {
        if (msg.sender != address(weth)) revert OnlyWETH();
    }

    /// @inheritdoc IRouter
    function sortTokens(address tokenA, address tokenB) public pure returns (address token0, address token1) {
        if (tokenA == tokenB) revert SameAddresses();
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        if (token0 == address(0)) revert ZeroAddress();
    }

    /// @inheritdoc IRouter
    function poolFor(address tokenA, address tokenB, bool stable, address _factory) public view returns (address pool) {
        address _defaultFactory = defaultFactory;
        address factory = _factory == address(0) ? _defaultFactory : _factory;
        if (!IFactoryRegistry(factoryRegistry).isPoolFactoryApproved(factory)) revert PoolFactoryDoesNotExist();

        (address token0, address token1) = sortTokens(tokenA, tokenB);
        bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable));
        pool = Clones.predictDeterministicAddress(IPoolFactory(factory).implementation(), salt, factory);
    }

    /// @dev given some amount of an asset and pool reserves, returns an equivalent amount of the other asset
    /// @dev this only accounts for volatile pools and may return insufficient liquidity for stable pools
    function quoteLiquidity(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) internal pure returns (uint256 amountB) {
        if (amountA == 0) revert InsufficientAmount();
        if (reserveA == 0 || reserveB == 0) revert InsufficientLiquidity();
        amountB = (amountA * reserveB) / reserveA;
    }

    /// @inheritdoc IRouter
    function getReserves(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory
    ) public view returns (uint256 reserveA, uint256 reserveB) {
        (address token0, ) = sortTokens(tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1, ) = IPool(poolFor(tokenA, tokenB, stable, _factory)).getReserves();
        (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    /// @inheritdoc IRouter
    function getAmountsOut(uint256 amountIn, Route[] memory routes) public view returns (uint256[] memory amounts) {
        if (routes.length < 1) revert InvalidPath();
        amounts = new uint256[](routes.length + 1);
        amounts[0] = amountIn;
        uint256 _length = routes.length;
        for (uint256 i = 0; i < _length; i++) {
            address factory = routes[i].factory == address(0) ? defaultFactory : routes[i].factory; // default to v2
            address pool = poolFor(routes[i].from, routes[i].to, routes[i].stable, factory);
            if (IPoolFactory(factory).isPool(pool)) {
                amounts[i + 1] = IPool(pool).getAmountOut(amounts[i], routes[i].from);
            }
        }
    }

    /// @inheritdoc IRouter
    function quoteAddLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 amountADesired,
        uint256 amountBDesired
    ) public view returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
        address _pool = IPoolFactory(_factory).getPool(tokenA, tokenB, stable);
        (uint256 reserveA, uint256 reserveB) = (0, 0);
        uint256 _totalSupply = 0;
        if (_pool != address(0)) {
            _totalSupply = IERC20(_pool).totalSupply();
            (reserveA, reserveB) = getReserves(tokenA, tokenB, stable, _factory);
        }
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
            liquidity = Math.sqrt(amountA * amountB) - MINIMUM_LIQUIDITY;
        } else {
            uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                (amountA, amountB) = (amountADesired, amountBOptimal);
                liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB);
            } else {
                uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                (amountA, amountB) = (amountAOptimal, amountBDesired);
                liquidity = Math.min((amountA * _totalSupply) / reserveA, (amountB * _totalSupply) / reserveB);
            }
        }
    }

    /// @inheritdoc IRouter
    function quoteRemoveLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 liquidity
    ) public view returns (uint256 amountA, uint256 amountB) {
        address _pool = IPoolFactory(_factory).getPool(tokenA, tokenB, stable);

        if (_pool == address(0)) {
            return (0, 0);
        }

        (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable, _factory);
        uint256 _totalSupply = IERC20(_pool).totalSupply();

        amountA = (liquidity * reserveA) / _totalSupply; // using balances ensures pro-rata distribution
        amountB = (liquidity * reserveB) / _totalSupply; // using balances ensures pro-rata distribution
    }

    function _addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) internal returns (uint256 amountA, uint256 amountB) {
        if (amountADesired < amountAMin) revert InsufficientAmountADesired();
        if (amountBDesired < amountBMin) revert InsufficientAmountBDesired();
        // create the pool if it doesn't exist yet
        address _pool = IPoolFactory(defaultFactory).getPool(tokenA, tokenB, stable);
        if (_pool == address(0)) {
            _pool = IPoolFactory(defaultFactory).createPool(tokenA, tokenB, stable);
        }
        (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable, defaultFactory);
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                if (amountBOptimal < amountBMin) revert InsufficientAmountB();
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                if (amountAOptimal < amountAMin) revert InsufficientAmountA();
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
    }

    /// @inheritdoc IRouter
    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) public ensure(deadline) returns (uint256 amountA, uint256 amountB, uint256 liquidity) {
        (amountA, amountB) = _addLiquidity(
            tokenA,
            tokenB,
            stable,
            amountADesired,
            amountBDesired,
            amountAMin,
            amountBMin
        );
        address pool = poolFor(tokenA, tokenB, stable, defaultFactory);
        _safeTransferFrom(tokenA, _msgSender(), pool, amountA);
        _safeTransferFrom(tokenB, _msgSender(), pool, amountB);
        liquidity = IPool(pool).mint(to);
    }

    /// @inheritdoc IRouter
    function addLiquidityETH(
        address token,
        bool stable,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external payable ensure(deadline) returns (uint256 amountToken, uint256 amountETH, uint256 liquidity) {
        (amountToken, amountETH) = _addLiquidity(
            token,
            address(weth),
            stable,
            amountTokenDesired,
            msg.value,
            amountTokenMin,
            amountETHMin
        );
        address pool = poolFor(token, address(weth), stable, defaultFactory);
        _safeTransferFrom(token, _msgSender(), pool, amountToken);
        weth.deposit{value: amountETH}();
        assert(weth.transfer(pool, amountETH));
        liquidity = IPool(pool).mint(to);
        // refund dust eth, if any
        if (msg.value > amountETH) _safeTransferETH(_msgSender(), msg.value - amountETH);
    }

    // **** REMOVE LIQUIDITY ****

    /// @inheritdoc IRouter
    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) public ensure(deadline) returns (uint256 amountA, uint256 amountB) {
        address pool = poolFor(tokenA, tokenB, stable, defaultFactory);
        IERC20(pool).safeTransferFrom(_msgSender(), pool, liquidity);
        (uint256 amount0, uint256 amount1) = IPool(pool).burn(to);
        (address token0, ) = sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        if (amountA < amountAMin) revert InsufficientAmountA();
        if (amountB < amountBMin) revert InsufficientAmountB();
    }

    /// @inheritdoc IRouter
    function removeLiquidityETH(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {
        (amountToken, amountETH) = removeLiquidity(
            token,
            address(weth),
            stable,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        _safeTransfer(token, to, amountToken);
        weth.withdraw(amountETH);
        _safeTransferETH(to, amountETH);
    }

    // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public ensure(deadline) returns (uint256 amountETH) {
        (, amountETH) = removeLiquidity(
            token,
            address(weth),
            stable,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        _safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
        weth.withdraw(amountETH);
        _safeTransferETH(to, amountETH);
    }

    // **** SWAP ****
    /// @dev requires the initial amount to have already been sent to the first pool
    function _swap(uint256[] memory amounts, Route[] memory routes, address _to) internal virtual {
        uint256 _length = routes.length;
        for (uint256 i = 0; i < _length; i++) {
            (address token0, ) = sortTokens(routes[i].from, routes[i].to);
            uint256 amountOut = amounts[i + 1];
            (uint256 amount0Out, uint256 amount1Out) = routes[i].from == token0
                ? (uint256(0), amountOut)
                : (amountOut, uint256(0));
            address to = i < routes.length - 1
                ? poolFor(routes[i + 1].from, routes[i + 1].to, routes[i + 1].stable, routes[i + 1].factory)
                : _to;
            IPool(poolFor(routes[i].from, routes[i].to, routes[i].stable, routes[i].factory)).swap(
                amount0Out,
                amount1Out,
                to,
                new bytes(0)
            );
        }
    }

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256[] memory amounts) {
        amounts = getAmountsOut(amountIn, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        _safeTransferFrom(
            routes[0].from,
            _msgSender(),
            poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory),
            amounts[0]
        );
        _swap(amounts, routes, to);
    }

    function swapExactETHForTokens(
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external payable ensure(deadline) returns (uint256[] memory amounts) {
        if (routes[0].from != address(weth)) revert InvalidPath();
        amounts = getAmountsOut(msg.value, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        weth.deposit{value: amounts[0]}();
        assert(weth.transfer(poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amounts[0]));
        _swap(amounts, routes, to);
    }

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256[] memory amounts) {
        if (routes[routes.length - 1].to != address(weth)) revert InvalidPath();
        amounts = getAmountsOut(amountIn, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        _safeTransferFrom(
            routes[0].from,
            _msgSender(),
            poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory),
            amounts[0]
        );
        _swap(amounts, routes, address(this));
        weth.withdraw(amounts[amounts.length - 1]);
        _safeTransferETH(to, amounts[amounts.length - 1]);
    }

    function UNSAFE_swapExactTokensForTokens(
        uint256[] memory amounts,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) returns (uint256[] memory) {
        _safeTransferFrom(
            routes[0].from,
            _msgSender(),
            poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory),
            amounts[0]
        );
        _swap(amounts, routes, to);
        return amounts;
    }

    // **** SWAP (supporting fee-on-transfer tokens) ****
    /// @dev requires the initial amount to have already been sent to the first pool
    function _swapSupportingFeeOnTransferTokens(Route[] memory routes, address _to) internal virtual {
        uint256 _length = routes.length;
        for (uint256 i; i < _length; i++) {
            (address token0, ) = sortTokens(routes[i].from, routes[i].to);
            address pool = poolFor(routes[i].from, routes[i].to, routes[i].stable, routes[i].factory);
            uint256 amountInput;
            uint256 amountOutput;
            {
                // stack too deep
                (uint256 reserveA, ) = getReserves(routes[i].from, routes[i].to, routes[i].stable, routes[i].factory); // getReserves sorts it for us i.e. reserveA is always for from
                amountInput = IERC20(routes[i].from).balanceOf(pool) - reserveA;
            }
            amountOutput = IPool(pool).getAmountOut(amountInput, routes[i].from);
            (uint256 amount0Out, uint256 amount1Out) = routes[i].from == token0
                ? (uint256(0), amountOutput)
                : (amountOutput, uint256(0));
            address to = i < routes.length - 1
                ? poolFor(routes[i + 1].from, routes[i + 1].to, routes[i + 1].stable, routes[i + 1].factory)
                : _to;
            IPool(pool).swap(amount0Out, amount1Out, to, new bytes(0));
        }
    }

    /// @inheritdoc IRouter
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) {
        _safeTransferFrom(
            routes[0].from,
            _msgSender(),
            poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory),
            amountIn
        );
        uint256 _length = routes.length - 1;
        uint256 balanceBefore = IERC20(routes[_length].to).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(routes, to);
        if (IERC20(routes[_length].to).balanceOf(to) - balanceBefore < amountOutMin) revert InsufficientOutputAmount();
    }

    /// @inheritdoc IRouter
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external payable ensure(deadline) {
        if (routes[0].from != address(weth)) revert InvalidPath();
        uint256 amountIn = msg.value;
        weth.deposit{value: amountIn}();
        assert(weth.transfer(poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory), amountIn));
        uint256 _length = routes.length - 1;
        uint256 balanceBefore = IERC20(routes[_length].to).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(routes, to);
        if (IERC20(routes[_length].to).balanceOf(to) - balanceBefore < amountOutMin) revert InsufficientOutputAmount();
    }

    /// @inheritdoc IRouter
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        Route[] calldata routes,
        address to,
        uint256 deadline
    ) external ensure(deadline) {
        if (routes[routes.length - 1].to != address(weth)) revert InvalidPath();
        _safeTransferFrom(
            routes[0].from,
            _msgSender(),
            poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory),
            amountIn
        );
        _swapSupportingFeeOnTransferTokens(routes, address(this));
        uint256 amountOut = weth.balanceOf(address(this));
        if (amountOut < amountOutMin) revert InsufficientOutputAmount();
        weth.withdraw(amountOut);
        _safeTransferETH(to, amountOut);
    }

    /// @inheritdoc IRouter
    function zapIn(
        address tokenIn,
        uint256 amountInA,
        uint256 amountInB,
        Zap calldata zapInPool,
        Route[] calldata routesA,
        Route[] calldata routesB,
        address to,
        bool stake
    ) external payable returns (uint256 liquidity) {
        uint256 amountIn = amountInA + amountInB;
        address _tokenIn = tokenIn;
        uint256 value = msg.value;
        if (tokenIn == ETHER) {
            if (amountIn != value) revert InvalidAmountInForETHDeposit();
            _tokenIn = address(weth);
            weth.deposit{value: value}();
        } else {
            if (value != 0) revert InvalidTokenInForETHDeposit();
            _safeTransferFrom(_tokenIn, _msgSender(), address(this), amountIn);
        }

        _zapSwap(_tokenIn, amountInA, amountInB, zapInPool, routesA, routesB);
        _zapInLiquidity(zapInPool);
        address pool = poolFor(zapInPool.tokenA, zapInPool.tokenB, zapInPool.stable, zapInPool.factory);

        if (stake) {
            liquidity = IPool(pool).mint(address(this));
            address gauge = IVoter(voter).gauges(pool);
            IERC20(pool).safeApprove(address(gauge), liquidity);
            IGauge(gauge).deposit(liquidity, to);
            IERC20(pool).safeApprove(address(gauge), 0);
        } else {
            liquidity = IPool(pool).mint(to);
        }

        _returnAssets(tokenIn);
        _returnAssets(zapInPool.tokenA);
        _returnAssets(zapInPool.tokenB);
    }

    /// @dev Handles swap leg of zap in (i.e. convert tokenIn into tokenA and tokenB).
    function _zapSwap(
        address tokenIn,
        uint256 amountInA,
        uint256 amountInB,
        Zap calldata zapInPool,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) internal {
        address tokenA = zapInPool.tokenA;
        address tokenB = zapInPool.tokenB;
        bool stable = zapInPool.stable;
        address factory = zapInPool.factory;
        address pool = poolFor(tokenA, tokenB, stable, factory);

        {
            (uint256 reserve0, uint256 reserve1, ) = IPool(pool).getReserves();
            if (reserve0 <= MINIMUM_LIQUIDITY || reserve1 <= MINIMUM_LIQUIDITY) revert PoolDoesNotExist();
        }

        if (tokenIn != tokenA) {
            if (routesA[routesA.length - 1].to != tokenA) revert InvalidRouteA();
            _internalSwap(tokenIn, amountInA, zapInPool.amountOutMinA, routesA);
        }
        if (tokenIn != tokenB) {
            if (routesB[routesB.length - 1].to != tokenB) revert InvalidRouteB();
            _internalSwap(tokenIn, amountInB, zapInPool.amountOutMinB, routesB);
        }
    }

    /// @dev Handles liquidity adding component of zap in.
    function _zapInLiquidity(Zap calldata zapInPool) internal {
        address tokenA = zapInPool.tokenA;
        address tokenB = zapInPool.tokenB;
        bool stable = zapInPool.stable;
        address factory = zapInPool.factory;
        address pool = poolFor(tokenA, tokenB, stable, factory);
        (uint256 amountA, uint256 amountB) = _quoteZapLiquidity(
            tokenA,
            tokenB,
            stable,
            factory,
            IERC20(tokenA).balanceOf(address(this)),
            IERC20(tokenB).balanceOf(address(this)),
            zapInPool.amountAMin,
            zapInPool.amountBMin
        );
        _safeTransfer(tokenA, pool, amountA);
        _safeTransfer(tokenB, pool, amountB);
    }

    /// @dev Similar to _addLiquidity. Assumes a pool exists, and accepts a factory argument.
    function _quoteZapLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin
    ) internal view returns (uint256 amountA, uint256 amountB) {
        if (amountADesired < amountAMin) revert InsufficientAmountADesired();
        if (amountBDesired < amountBMin) revert InsufficientAmountBDesired();
        (uint256 reserveA, uint256 reserveB) = getReserves(tokenA, tokenB, stable, _factory);
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint256 amountBOptimal = quoteLiquidity(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                if (amountBOptimal < amountBMin) revert InsufficientAmountB();
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = quoteLiquidity(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                if (amountAOptimal < amountAMin) revert InsufficientAmountA();
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
        }
    }

    /// @dev Handles swaps internally for zaps.
    function _internalSwap(address tokenIn, uint256 amountIn, uint256 amountOutMin, Route[] memory routes) internal {
        uint256[] memory amounts = getAmountsOut(amountIn, routes);
        if (amounts[amounts.length - 1] < amountOutMin) revert InsufficientOutputAmount();
        address pool = poolFor(routes[0].from, routes[0].to, routes[0].stable, routes[0].factory);
        _safeTransfer(tokenIn, pool, amountIn);
        _swap(amounts, routes, address(this));
    }

    /// @inheritdoc IRouter
    function zapOut(
        address tokenOut,
        uint256 liquidity,
        Zap calldata zapOutPool,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) external {
        address tokenA = zapOutPool.tokenA;
        address tokenB = zapOutPool.tokenB;
        address _tokenOut = (tokenOut == ETHER) ? address(weth) : tokenOut;
        _zapOutLiquidity(liquidity, zapOutPool);

        uint256 balance;
        if (tokenA != _tokenOut) {
            balance = IERC20(tokenA).balanceOf(address(this));
            if (routesA[routesA.length - 1].to != _tokenOut) revert InvalidRouteA();
            _internalSwap(tokenA, balance, zapOutPool.amountOutMinA, routesA);
        }
        if (tokenB != _tokenOut) {
            balance = IERC20(tokenB).balanceOf(address(this));
            if (routesB[routesB.length - 1].to != _tokenOut) revert InvalidRouteB();
            _internalSwap(tokenB, balance, zapOutPool.amountOutMinB, routesB);
        }

        _returnAssets(tokenOut);
    }

    /// @dev Handles liquidity removing component of zap out.
    function _zapOutLiquidity(uint256 liquidity, Zap calldata zapOutPool) internal {
        address tokenA = zapOutPool.tokenA;
        address tokenB = zapOutPool.tokenB;
        address pool = poolFor(tokenA, tokenB, zapOutPool.stable, zapOutPool.factory);
        IERC20(pool).safeTransferFrom(msg.sender, pool, liquidity);
        (address token0, ) = sortTokens(tokenA, tokenB);
        (uint256 amount0, uint256 amount1) = IPool(pool).burn(address(this));
        (uint256 amountA, uint256 amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        if (amountA < zapOutPool.amountAMin) revert InsufficientAmountA();
        if (amountB < zapOutPool.amountBMin) revert InsufficientAmountB();
    }

    /// @inheritdoc IRouter
    function generateZapInParams(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 amountInA,
        uint256 amountInB,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin) {
        amountOutMinA = amountInA;
        amountOutMinB = amountInB;
        uint256[] memory amounts;
        if (routesA.length > 0) {
            amounts = getAmountsOut(amountInA, routesA);
            amountOutMinA = amounts[amounts.length - 1];
        }
        if (routesB.length > 0) {
            amounts = getAmountsOut(amountInB, routesB);
            amountOutMinB = amounts[amounts.length - 1];
        }
        (amountAMin, amountBMin, ) = quoteAddLiquidity(tokenA, tokenB, stable, _factory, amountOutMinA, amountOutMinB);
    }

    /// @inheritdoc IRouter
    function generateZapOutParams(
        address tokenA,
        address tokenB,
        bool stable,
        address _factory,
        uint256 liquidity,
        Route[] calldata routesA,
        Route[] calldata routesB
    ) external view returns (uint256 amountOutMinA, uint256 amountOutMinB, uint256 amountAMin, uint256 amountBMin) {
        (amountAMin, amountBMin) = quoteRemoveLiquidity(tokenA, tokenB, stable, _factory, liquidity);
        amountOutMinA = amountAMin;
        amountOutMinB = amountBMin;
        uint256[] memory amounts;
        if (routesA.length > 0) {
            amounts = getAmountsOut(amountAMin, routesA);
            amountOutMinA = amounts[amounts.length - 1];
        }
        if (routesB.length > 0) {
            amounts = getAmountsOut(amountBMin, routesB);
            amountOutMinB = amounts[amounts.length - 1];
        }
    }

    /// @dev Return residual assets from zapping.
    /// @param token token to return, put `ETHER` if you want Ether back.
    function _returnAssets(address token) internal {
        address sender = _msgSender();
        uint256 balance;
        if (token == ETHER) {
            balance = IERC20(weth).balanceOf(address(this));
            if (balance > 0) {
                IWETH(weth).withdraw(balance);
                _safeTransferETH(sender, balance);
            }
        } else {
            balance = IERC20(token).balanceOf(address(this));
            if (balance > 0) {
                IERC20(token).safeTransfer(sender, balance);
            }
        }
    }

    /// @inheritdoc IRouter
    function quoteStableLiquidityRatio(
        address tokenA,
        address tokenB,
        address _factory
    ) external view returns (uint256 ratio) {
        IPool pool = IPool(poolFor(tokenA, tokenB, true, _factory));

        uint256 decimalsA = 10 ** IERC20Metadata(tokenA).decimals();
        uint256 decimalsB = 10 ** IERC20Metadata(tokenB).decimals();

        uint256 investment = decimalsA;
        uint256 out = pool.getAmountOut(investment, tokenA);
        (uint256 amountA, uint256 amountB, ) = quoteAddLiquidity(tokenA, tokenB, true, _factory, investment, out);

        amountA = (amountA * 1e18) / decimalsA;
        amountB = (amountB * 1e18) / decimalsB;
        out = (out * 1e18) / decimalsB;
        investment = (investment * 1e18) / decimalsA;

        ratio = (((out * 1e18) / investment) * amountA) / amountB;

        return (investment * 1e18) / (ratio + 1e18);
    }

    function _safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        if (!success) revert ETHTransferFailed();
    }

    function _safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0);
        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"},{"internalType":"address","name":"_factoryRegistry","type":"address"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_voter","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InsufficientAmountA","type":"error"},{"inputs":[],"name":"InsufficientAmountADesired","type":"error"},{"inputs":[],"name":"InsufficientAmountAOptimal","type":"error"},{"inputs":[],"name":"InsufficientAmountB","type":"error"},{"inputs":[],"name":"InsufficientAmountBDesired","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InvalidAmountInForETHDeposit","type":"error"},{"inputs":[],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"InvalidRouteA","type":"error"},{"inputs":[],"name":"InvalidRouteB","type":"error"},{"inputs":[],"name":"InvalidTokenInForETHDeposit","type":"error"},{"inputs":[],"name":"OnlyWETH","type":"error"},{"inputs":[],"name":"PoolDoesNotExist","type":"error"},{"inputs":[],"name":"PoolFactoryDoesNotExist","type":"error"},{"inputs":[],"name":"SameAddresses","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ETHER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"UNSAFE_swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"defaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"amountInA","type":"uint256"},{"internalType":"uint256","name":"amountInB","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"}],"name":"generateZapInParams","outputs":[{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"}],"name":"generateZapOutParams","outputs":[{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"}],"name":"getReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"}],"name":"poolFor","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"}],"name":"quoteAddLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"_factory","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"quoteRemoveLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"address","name":"_factory","type":"address"}],"name":"quoteStableLiquidityRatio","outputs":[{"internalType":"uint256","name":"ratio","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"sortTokens","outputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routes","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountInA","type":"uint256"},{"internalType":"uint256","name":"amountInB","type":"uint256"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"internalType":"struct IRouter.Zap","name":"zapInPool","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stake","type":"bool"}],"name":"zapIn","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"uint256","name":"amountOutMinA","type":"uint256"},{"internalType":"uint256","name":"amountOutMinB","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"}],"internalType":"struct IRouter.Zap","name":"zapOutPool","type":"tuple"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesA","type":"tuple[]"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"},{"internalType":"address","name":"factory","type":"address"}],"internalType":"struct IRouter.Route[]","name":"routesB","type":"tuple[]"}],"name":"zapOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b5060405162005e4a38038062005e4a83398101604081905262000035916200007c565b6001600160a01b0394851660805292841660a05290831660c052821660e0521661010052620000ec565b80516001600160a01b03811681146200007757600080fd5b919050565b600080600080600060a086880312156200009557600080fd5b620000a0866200005f565b9450620000b0602087016200005f565b9350620000c0604087016200005f565b9250620000d0606087016200005f565b9150620000e0608087016200005f565b90509295509295909350565b60805160a05160c05160e05161010051615c1d6200022d600039600081816101d6015281816103260152818161097301528181610b4901528181610bf501528181610c7901528181610cf801528181610d6c01528181611b7001528181611c8501528181611d1301528181611e9601528181612179015281816121af015281816122050152818161229a015281816123cc0152818161259e01528181612aca01528181612b1a01528181612e6101528181612e84015281816131eb015281816132a40152818161410301526141940152600081816103af01526130280152600081816106210152818161081d015281816112e70152818161150b01528181611713015281816121d101528181613c6a01528181613d0b0152613d950152600081816102c7015261176c01526000818161044e01526133460152615c1d6000f3fe6080604052600436106101c65760003560e01c8063874029d9116100f7578063c92de3ec11610095578063d7b0e0a511610064578063d7b0e0a514610643578063f5ba53c714610663578063fb49bafd14610691578063fe411f14146106a457600080fd5b8063c92de3ec146105af578063cac88ea9146105cf578063ce700c29146105ef578063d4b6846d1461060f57600080fd5b8063903638a4116100d1578063903638a414610549578063a81b91591461055c578063b7e0d4c01461057c578063c6b7f1b61461058f57600080fd5b8063874029d9146104e957806388cd821e146105095780638c0037dc1461052957600080fd5b806342cb1fbc116101645780635509a1ac1161013e5780635509a1ac14610411578063572b6c05146104315780635a47ddc31461048e5780637539d413146104c957600080fd5b806342cb1fbc1461037557806346c96aac1461039d578063544caa56146103d157600080fd5b80633bf0c9fb116101a05780633bf0c9fb146102b55780633da5acba146103015780633fc8cef3146103145780634111d5971461034857600080fd5b806307db50fa1461021b5780630dede6c41461026057806312bc3aca1461029557600080fd5b3661021657336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610214576040516301f180c960e01b815260040160405180910390fd5b005b600080fd5b34801561022757600080fd5b5061023b610236366004614e56565b6106c4565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561026c57600080fd5b5061028061027b366004614f26565b610806565b60408051928352602083019190915201610257565b3480156102a157600080fd5b506102146102b0366004614fab565b61095f565b3480156102c157600080fd5b506102e97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610257565b61021461030f36600461501d565b610c6d565b34801561032057600080fd5b506102e97f000000000000000000000000000000000000000000000000000000000000000081565b34801561035457600080fd5b506103686103633660046150ec565b610ffe565b60405161025791906151b7565b34801561038157600080fd5b506102e973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b3480156103a957600080fd5b506102e97f000000000000000000000000000000000000000000000000000000000000000081565b3480156103dd57600080fd5b506103f16103ec3660046151fb565b61115e565b604080516001600160a01b03938416815292909116602083015201610257565b34801561041d57600080fd5b5061036861042c3660046152bc565b6111e9565b34801561043d57600080fd5b5061047e61044c366004615363565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6040519015158152602001610257565b34801561049a57600080fd5b506104ae6104a9366004615380565b6114de565b60408051938452602084019290925290820152606001610257565b3480156104d557600080fd5b5061023b6104e436600461540f565b6115d6565b3480156104f557600080fd5b506102e96105043660046154d4565b61170f565b34801561051557600080fd5b50610214610524366004614fab565b611927565b34801561053557600080fd5b506102806105443660046154d4565b611aa8565b61036861055736600461501d565b611b62565b34801561056857600080fd5b50610214610577366004615549565b611e43565b6104ae61058a3660046155e9565b612164565b34801561059b57600080fd5b506103686105aa366004614fab565b6123b6565b3480156105bb57600080fd5b506102806105ca36600461565b565b61267d565b3480156105db57600080fd5b506103686105ea366004614fab565b6127c6565b3480156105fb57600080fd5b506104ae61060a3660046156bf565b6128d5565b34801561061b57600080fd5b506102e97f000000000000000000000000000000000000000000000000000000000000000081565b34801561064f57600080fd5b5061028061065e3660046155e9565b612ab7565b34801561066f57600080fd5b5061068361067e36600461572d565b612b95565b604051908152602001610257565b61068361069f366004615778565b612e09565b3480156106b057600080fd5b506106836106bf3660046155e9565b6131d9565b8585600080606087156107595761072d8b8a8a808060200260200160405190810160405280939291908181526020016000905b828210156107235761071460808302860136819003810190615849565b815260200190600101906106f7565b50505050506111e9565b9050806001825161073e919061587b565b8151811061074e5761074e61588e565b602002602001015194505b85156107dd576107b18a8888808060200260200160405190810160405280939291908181526020016000905b82821015610723576107a260808302860136819003810190615849565b81526020019060010190610785565b905080600182516107c2919061587b565b815181106107d2576107d261588e565b602002602001015193505b6107eb8f8f8f8f89896128d5565b508093508194505050509a509a509a509a9650505050505050565b600080826108138161331e565b60006108418c8c8c7f000000000000000000000000000000000000000000000000000000000000000061170f565b905061086061084e613342565b6001600160a01b03831690838c613386565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af11580156108ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d091906158a4565b9150915060006108e08f8f61115e565b509050806001600160a01b03168f6001600160a01b031614610903578183610906565b82825b90975095508a87101561092c576040516323d9bb0560e21b815260040160405180910390fd5b8986101561094d57604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b806109698161331e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001685856109a060018261587b565b8181106109af576109af61588e565b90506080020160200160208101906109c79190615363565b6001600160a01b0316146109ee576040516320db826760e01b815260040160405180910390fd5b610ad585856000818110610a0457610a0461588e565b610a1a9260206080909202019081019150615363565b610a22613342565b610acf88886000818110610a3857610a3861588e565b610a4e9260206080909202019081019150615363565b89896000818110610a6157610a6161588e565b9050608002016020016020810190610a799190615363565b8a8a6000818110610a8c57610a8c61588e565b9050608002016040016020810190610aa491906158c8565b8b8b6000818110610ab757610ab761588e565b90506080020160600160208101906105049190615363565b8a6133f7565b610b318585808060200260200160405190810160405280939291908181526020016000905b82821015610b2657610b1760808302860136819003810190615849565b81526020019060010190610afa565b5050505050306134ef565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbc91906158e5565b905086811015610bdf576040516342301c2360e01b815260040160405180910390fd5b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b50505050610c638482613918565b5050505050505050565b80610c778161331e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031685856000818110610cb457610cb461588e565b610cca9260206080909202019081019150615363565b6001600160a01b031614610cf1576040516320db826760e01b815260040160405180910390fd5b60003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d5157600080fd5b505af1158015610d65573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb610daf88886000818110610a3857610a3861588e565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610dfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2091906158fe565b610e2c57610e2c61591b565b6000610e3960018761587b565b90506000878783818110610e4f57610e4f61588e565b9050608002016020016020810190610e679190615363565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa158015610eaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed391906158e5565b9050610f318888808060200260200160405190810160405280939291908181526020016000905b82821015610f2657610f1760808302860136819003810190615849565b81526020019060010190610efa565b5050505050876134ef565b8881898985818110610f4557610f4561588e565b9050608002016020016020810190610f5d9190615363565b6040516370a0823160e01b81526001600160a01b038a8116600483015291909116906370a08231906024015b602060405180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca91906158e5565b610fd4919061587b565b1015610ff3576040516342301c2360e01b815260040160405180910390fd5b505050505050505050565b60608161100a8161331e565b6110f3868660008181106110205761102061588e565b6110369260206080909202019081019150615363565b61103e613342565b6110d3898960008181106110545761105461588e565b61106a9260206080909202019081019150615363565b8a8a600081811061107d5761107d61588e565b90506080020160200160208101906110959190615363565b8b8b60008181106110a8576110a861588e565b90506080020160400160208101906110c091906158c8565b8c8c6000818110610ab757610ab761588e565b8a6000815181106110e6576110e661588e565b60200260200101516133f7565b611150878787808060200260200160405190810160405280939291908181526020016000905b828210156111455761113660808302860136819003810190615849565b81526020019060010190611119565b5050505050866139ab565b8691505b5095945050505050565b600080826001600160a01b0316846001600160a01b03160361119357604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b0316106111b35782846111b6565b83835b90925090506001600160a01b0382166111e25760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b606060018251101561120e576040516320db826760e01b815260040160405180910390fd5b815161121b906001615931565b6001600160401b0381111561123257611232615083565b60405190808252806020026020018201604052801561125b578160200160208202803683370190505b50905082816000815181106112725761127261588e565b6020908102919091010152815160005b818110156114d6576000806001600160a01b03168583815181106112a8576112a861588e565b6020026020010151606001516001600160a01b0316146112e5578482815181106112d4576112d461588e565b602002602001015160600151611307565b7f00000000000000000000000000000000000000000000000000000000000000005b9050600061136e8684815181106113205761132061588e565b60200260200101516000015187858151811061133e5761133e61588e565b60200260200101516020015188868151811061135c5761135c61588e565b6020026020010151604001518561170f565b604051635b16ebb760e01b81526001600160a01b03808316600483015291925090831690635b16ebb790602401602060405180830381865afa1580156113b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113dc91906158fe565b156114c157806001600160a01b031663f140a35a8685815181106114025761140261588e565b602002602001015188868151811061141c5761141c61588e565b6020026020010151600001516040518363ffffffff1660e01b81526004016114579291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149891906158e5565b856114a4856001615931565b815181106114b4576114b461588e565b6020026020010181815250505b505080806114ce90615944565b915050611282565b505092915050565b6000806000836114ed8161331e565b6114fc8d8d8d8d8d8d8d613c0b565b9094509250600061152f8e8e8e7f000000000000000000000000000000000000000000000000000000000000000061170f565b90506115448e61153d613342565b83886133f7565b6115578d611550613342565b83876133f7565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561159f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c391906158e5565b9250505099509950999650505050505050565b6000806000806115e98d8d8d8d8d61267d565b90945092508391508290506060871561167a5761164e838a8a808060200260200160405190810160405280939291908181526020016000905b828210156107235761163f60808302860136819003810190615849565b81526020019060010190611622565b9050806001825161165f919061587b565b8151811061166f5761166f61588e565b602002602001015194505b85156116fe576116d2828888808060200260200160405190810160405280939291908181526020016000905b82821015610723576116c360808302860136819003810190615849565b815260200190600101906116a6565b905080600182516116e3919061587b565b815181106116f3576116f361588e565b602002602001015193505b509950995099509995505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000816001600160a01b03841615611748578361174a565b815b60405163d1ea0a1d60e01b81526001600160a01b0380831660048301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063d1ea0a1d90602401602060405180830381865afa1580156117b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d991906158fe565b6117f657604051634d39d5a360e11b815260040160405180910390fd5b600080611803898961115e565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015289151560f81b60488201529193509150600090604901604051602081830303815290604052805190602001209050611919846001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611898573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118bc919061595d565b604051603881018790526f5af43d82803e903d91602b57fd5bf3ff60248201526014810191909152733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018390526037600c8201206078820152605560439091012090565b9a9950505050505050505050565b806119318161331e565b61194785856000818110610a0457610a0461588e565b600061195460018661587b565b9050600086868381811061196a5761196a61588e565b90506080020160200160208101906119829190615363565b6040516370a0823160e01b81526001600160a01b03878116600483015291909116906370a0823190602401602060405180830381865afa1580156119ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ee91906158e5565b9050611a4c8787808060200260200160405190810160405280939291908181526020016000905b82821015611a4157611a3260808302860136819003810190615849565b81526020019060010190611a15565b5050505050866134ef565b8781888885818110611a6057611a6061588e565b9050608002016020016020810190611a789190615363565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401610f89565b6000806000611ab7878761115e565b509050600080611ac98989898961170f565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2a919061597a565b5091509150826001600160a01b0316896001600160a01b031614611b4f578082611b52565b81815b909a909950975050505050505050565b606081611b6e8161331e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031686866000818110611bab57611bab61588e565b611bc19260206080909202019081019150615363565b6001600160a01b031614611be8576040516320db826760e01b815260040160405180910390fd5b611c3a348787808060200260200160405190810160405280939291908181526020016000905b8282101561072357611c2b60808302860136819003810190615849565b81526020019060010190611c0e565b9150868260018451611c4c919061587b565b81518110611c5c57611c5c61588e565b60200260200101511015611c83576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110611cc557611cc561588e565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cf857600080fd5b505af1158015611d0c573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb611d5688886000818110610a3857610a3861588e565b84600081518110611d6957611d6961588e565b60200260200101516040518363ffffffff1660e01b8152600401611da29291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015611dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de591906158fe565b611df157611df161591b565b611154828787808060200260200160405190810160405280939291908181526020016000905b8282101561114557611e3460808302860136819003810190615849565b81526020019060010190611e17565b6000611e526020870187615363565b90506000611e666040880160208901615363565b905060006001600160a01b038a1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611e945789611eb6565b7f00000000000000000000000000000000000000000000000000000000000000005b9050611ec28989613e74565b6000816001600160a01b0316846001600160a01b03161461200e576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015611f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4591906158e5565b90506001600160a01b0382168888611f5e60018261587b565b818110611f6d57611f6d61588e565b9050608002016020016020810190611f859190615363565b6001600160a01b031614611fac576040516309d41c6760e31b815260040160405180910390fd5b61200e84828b608001358b8b808060200260200160405190810160405280939291908181526020016000905b8282101561200457611ff560808302860136819003810190615849565b81526020019060010190611fd8565b5050505050613fd9565b816001600160a01b0316836001600160a01b03161461214e576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f91906158e5565b90506001600160a01b03821686866120a860018261587b565b8181106120b7576120b761588e565b90506080020160200160208101906120cf9190615363565b6001600160a01b0316146120f6576040516332b2410360e21b815260040160405180910390fd5b61214e83828b60a001358989808060200260200160405190810160405280939291908181526020016000905b828210156120045761213f60808302860136819003810190615849565b81526020019060010190612122565b6121578b6140bb565b5050505050505050505050565b6000806000836121738161331e565b6121a28b7f00000000000000000000000000000000000000000000000000000000000000008c8c348d8d613c0b565b909450925060006121f58c7f00000000000000000000000000000000000000000000000000000000000000008d7f000000000000000000000000000000000000000000000000000000000000000061170f565b90506122038c61153d613342565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561225e57600080fd5b505af1158015612272573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af11580156122e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230b91906158fe565b6123175761231761591b565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561235f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238391906158e5565b9250833411156123a7576123a7612398613342565b6123a2863461587b565b613918565b50509750975097945050505050565b6060816123c28161331e565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001686866123f960018261587b565b8181106124085761240861588e565b90506080020160200160208101906124209190615363565b6001600160a01b031614612447576040516320db826760e01b815260040160405180910390fd5b612499888787808060200260200160405190810160405280939291908181526020016000905b828210156107235761248a60808302860136819003810190615849565b8152602001906001019061246d565b91508682600184516124ab919061587b565b815181106124bb576124bb61588e565b602002602001015110156124e2576040516342301c2360e01b815260040160405180910390fd5b61253f868660008181106124f8576124f861588e565b61250e9260206080909202019081019150615363565b612516613342565b61252c898960008181106110545761105461588e565b856000815181106110e6576110e661588e565b61259c828787808060200260200160405190810160405280939291908181526020016000905b828210156125915761258260808302860136819003810190615849565b81526020019060010190612565565b5050505050306139ab565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d83600185516125da919061587b565b815181106125ea576125ea61588e565b60200260200101516040518263ffffffff1660e01b815260040161261091815260200190565b600060405180830381600087803b15801561262a57600080fd5b505af115801561263e573d6000803e3d6000fd5b50505050612672848360018551612655919061587b565b815181106126655761266561588e565b6020026020010151613918565b509695505050505050565b6000806000846001600160a01b03166379bc57d58989896040518463ffffffff1660e01b81526004016126b2939291906159a8565b602060405180830381865afa1580156126cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f3919061595d565b90506001600160a01b0381166127105760008092509250506127bc565b60008061271f8a8a8a8a611aa8565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612763573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278791906158e5565b90508061279484896159cc565b61279e91906159f9565b9550806127ab83896159cc565b6127b591906159f9565b9450505050505b9550959350505050565b6060816127d28161331e565b612824888787808060200260200160405190810160405280939291908181526020016000905b828210156107235761281560808302860136819003810190615849565b815260200190600101906127f8565b9150868260018451612836919061587b565b815181106128465761284661588e565b6020026020010151101561286d576040516342301c2360e01b815260040160405180910390fd5b612883868660008181106124f8576124f861588e565b612672828787808060200260200160405190810160405280939291908181526020016000905b82821015611145576128c660808302860136819003810190615849565b815260200190600101906128a9565b600080600080866001600160a01b03166379bc57d58b8b8b6040518463ffffffff1660e01b815260040161290b939291906159a8565b602060405180830381865afa158015612928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061294c919061595d565b9050600080806001600160a01b038416156129d757836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561299f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c391906158e5565b90506129d18d8d8d8d611aa8565b90935091505b821580156129e3575081155b15612a14578896508795506103e8612a036129fe888a6159cc565b614286565b612a0d919061587b565b9450612aa7565b6000612a218a8585614375565b9050888111612a6957899750955085612a6284612a3e848b6159cc565b612a4891906159f9565b84612a53858b6159cc565b612a5d91906159f9565b6143de565b9550612aa5565b6000612a768a8587614375565b9850899750889050612aa185612a8c85846159cc565b612a9691906159f9565b85612a53868c6159cc565b9650505b505b5050505096509650969350505050565b60008082612ac48161331e565b612af48a7f00000000000000000000000000000000000000000000000000000000000000008b8b8b8b308b610806565b9093509150612b048a86856143f8565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612b6657600080fd5b505af1158015612b7a573d6000803e3d6000fd5b50505050612b888583613918565b5097509795505050505050565b600080612ba5858560018661170f565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0b9190615a1b565b612c1690600a615b22565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7c9190615a1b565b612c8790600a615b22565b6040516378a051ad60e11b8152600481018490526001600160a01b03898116602483015291925083916000919086169063f140a35a90604401602060405180830381865afa158015612cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0191906158e5565b9050600080612d158b8b60018c88886128d5565b50909250905085612d2e83670de0b6b3a76400006159cc565b612d3891906159f9565b915084612d4d82670de0b6b3a76400006159cc565b612d5791906159f9565b905084612d6c84670de0b6b3a76400006159cc565b612d7691906159f9565b925085612d8b85670de0b6b3a76400006159cc565b612d9591906159f9565b9350808285612dac86670de0b6b3a76400006159cc565b612db691906159f9565b612dc091906159cc565b612dca91906159f9565b9750612dde88670de0b6b3a7640000615931565b612df085670de0b6b3a76400006159cc565b612dfa91906159f9565b9b9a5050505050505050505050565b600080612e168a8c615931565b90508b3473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601612efb57808314612e5f57604051633851fdc960e11b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612edd57600080fd5b505af1158015612ef1573d6000803e3d6000fd5b5050505050612f2d565b8015612f1a5760405163ae6d566f60e01b815260040160405180910390fd5b612f2d82612f26613342565b30866133f7565b612f3d828e8e8e8e8e8e8e6144e0565b612f468b614795565b6000612f91612f5860208e018e615363565b8d6020016020810190612f6b9190615363565b8e6040016020810190612f7e91906158c8565b8f60600160208101906105049190615363565b90508515613127576040516335313c2160e11b81523060048201526001600160a01b03821690636a627842906024016020604051808303816000875af1158015612fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300391906158e5565b60405163b9a09fd560e01b81526001600160a01b0383811660048301529196506000917f0000000000000000000000000000000000000000000000000000000000000000169063b9a09fd590602401602060405180830381865afa15801561306f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613093919061595d565b90506130a96001600160a01b03831682886148fd565b604051636e553f6560e01b8152600481018790526001600160a01b038981166024830152821690636e553f6590604401600060405180830381600087803b1580156130f357600080fd5b505af1158015613107573d6000803e3d6000fd5b50613121925050506001600160a01b0383168260006148fd565b50613196565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561316f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319391906158e5565b94505b61319f8f6140bb565b6131b46131af60208e018e615363565b6140bb565b6131c76131af60408e0160208f01615363565b505050509a9950505050505050505050565b6000816131e58161331e565b613215897f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a308a610806565b6040516370a0823160e01b815230600482015290935061328e91508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa158015613265573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328991906158e5565b6143f8565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156132f057600080fd5b505af1158015613304573d6000803e3d6000fd5b505050506133128483613918565b50979650505050505050565b4281101561333f57604051630407b05b60e31b815260040160405180910390fd5b50565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303613381575060131936013560601c90565b503390565b6040516001600160a01b03808516602483015283166044820152606481018290526133f19085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a17565b50505050565b6000846001600160a01b03163b1161340e57600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916134729190615b55565b6000604051808303816000865af19150503d80600081146134af576040519150601f19603f3d011682016040523d82523d6000602084013e6134b4565b606091505b50915091508180156134de5750805115806134de5750808060200190518101906134de91906158fe565b6134e757600080fd5b505050505050565b815160005b818110156133f15760006135428583815181106135135761351361588e565b6020026020010151600001518684815181106135315761353161588e565b60200260200101516020015161115e565b50905060006135c786848151811061355c5761355c61588e565b60200260200101516000015187858151811061357a5761357a61588e565b6020026020010151602001518886815181106135985761359861588e565b6020026020010151604001518987815181106135b6576135b661588e565b60200260200101516060015161170f565b9050600080600061364e8987815181106135e3576135e361588e565b6020026020010151600001518a88815181106136015761360161588e565b6020026020010151602001518b898151811061361f5761361f61588e565b6020026020010151604001518c8a8151811061363d5761363d61588e565b602002602001015160600151611aa8565b509050808987815181106136645761366461588e565b6020908102919091010151516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a0823190602401602060405180830381865afa1580156136b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136db91906158e5565b6136e5919061587b565b925050826001600160a01b031663f140a35a838a888151811061370a5761370a61588e565b6020026020010151600001516040518363ffffffff1660e01b81526004016137459291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613762573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378691906158e5565b9050600080856001600160a01b03168a88815181106137a7576137a761588e565b6020026020010151600001516001600160a01b0316146137c9578260006137cd565b6000835b91509150600060018b516137e1919061587b565b88106137ed578961388a565b61388a8b6137fc8a6001615931565b8151811061380c5761380c61588e565b6020026020010151600001518c8a60016138269190615931565b815181106138365761383661588e565b6020026020010151602001518d8b60016138509190615931565b815181106138605761386061588e565b6020026020010151604001518e8c600161387a9190615931565b815181106135b6576135b661588e565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f906138cc9086908690869060248101615b9d565b600060405180830381600087803b1580156138e657600080fd5b505af11580156138fa573d6000803e3d6000fd5b5050505050505050505050808061391090615944565b9150506134f4565b604080516000808252602082019092526001600160a01b0384169083906040516139429190615b55565b60006040518083038185875af1925050503d806000811461397f576040519150601f19603f3d011682016040523d82523d6000602084013e613984565b606091505b50509050806139a65760405163b12d13eb60e01b815260040160405180910390fd5b505050565b815160005b81811015613c045760006139cf8583815181106135135761351361588e565b5090506000866139e0846001615931565b815181106139f0576139f061588e565b60200260200101519050600080836001600160a01b0316888681518110613a1957613a1961588e565b6020026020010151600001516001600160a01b031614613a3b57826000613a3f565b6000835b91509150600060018951613a53919061587b565b8610613a5f5787613aec565b613aec89613a6e886001615931565b81518110613a7e57613a7e61588e565b6020026020010151600001518a886001613a989190615931565b81518110613aa857613aa861588e565b6020026020010151602001518b896001613ac29190615931565b81518110613ad257613ad261588e565b6020026020010151604001518c8a600161387a9190615931565b9050613b5d898781518110613b0357613b0361588e565b6020026020010151600001518a8881518110613b2157613b2161588e565b6020026020010151602001518b8981518110613b3f57613b3f61588e565b6020026020010151604001518c8a815181106135b6576135b661588e565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613b9a576020820181803683370190505b506040518563ffffffff1660e01b8152600401613bba9493929190615b9d565b600060405180830381600087803b158015613bd457600080fd5b505af1158015613be8573d6000803e3d6000fd5b5050505050505050508080613bfc90615944565b9150506139b0565b5050505050565b60008083861015613c2f57604051636e35977960e11b815260040160405180910390fd5b82851015613c505760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906379bc57d590613ca3908d908d908d906004016159a8565b602060405180830381865afa158015613cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce4919061595d565b90506001600160a01b038116613d8a576040516301b5fcad60e51b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906336bf95a090613d44908d908d908d906004016159a8565b6020604051808303816000875af1158015613d63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d87919061595d565b90505b600080613db98c8c8c7f0000000000000000000000000000000000000000000000000000000000000000611aa8565b91509150816000148015613dcb575080155b15613ddb57889450879350613e65565b6000613de88a8484614375565b9050888111613e1d5786811015613e1257604051630d32418960e21b815260040160405180910390fd5b899550935083613e63565b6000613e2a8a8486614375565b90508a811115613e3c57613e3c61591b565b88811015613e5d576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b6000613e836020830183615363565b90506000613e976040840160208501615363565b90506000613ec08383613eb060608801604089016158c8565b6105046080890160608a01615363565b9050613ed76001600160a01b038216338388613386565b6000613ee3848461115e565b5060405163226bf2d160e21b815230600482015290915060009081906001600160a01b038516906389afcb449060240160408051808303816000875af1158015613f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f5591906158a4565b91509150600080846001600160a01b0316886001600160a01b031614613f7c578284613f7f565b83835b915091508860c00135821015613fa8576040516323d9bb0560e21b815260040160405180910390fd5b8860e00135811015613fcd57604051630d32418960e21b815260040160405180910390fd5b50505050505050505050565b6000613fe584836111e9565b9050828160018351613ff7919061587b565b815181106140075761400761588e565b6020026020010151101561402e576040516342301c2360e01b815260040160405180910390fd5b60006140a3836000815181106140465761404661588e565b602002602001015160000151846000815181106140655761406561588e565b602002602001015160200151856000815181106140845761408461588e565b602002602001015160400151866000815181106135b6576135b661588e565b90506140b08682876143f8565b6134e78284306139ab565b60006140c5613342565b9050600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601614202576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015614152573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417691906158e5565b905080156139a657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156141e057600080fd5b505af11580156141f4573d6000803e3d6000fd5b505050506139a68282613918565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015614246573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426a91906158e5565b905080156139a6576139a66001600160a01b0384168383614ae9565b60008160000361429857506000919050565b600060016142a584614b19565b901c6001901b905060018184816142be576142be6159e3565b048201901c905060018184816142d6576142d66159e3565b048201901c905060018184816142ee576142ee6159e3565b048201901c90506001818481614306576143066159e3565b048201901c9050600181848161431e5761431e6159e3565b048201901c90506001818481614336576143366159e3565b048201901c9050600181848161434e5761434e6159e3565b048201901c905061436e81828581614368576143686159e3565b046143de565b9392505050565b60008360000361439857604051632ca2f52b60e11b815260040160405180910390fd5b8215806143a3575081155b156143c15760405163bb55fd2760e01b815260040160405180910390fd5b826143cc83866159cc565b6143d691906159f9565b949350505050565b60008183106143ed57816143ef565b825b90505b92915050565b6000836001600160a01b03163b1161440f57600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161446b9190615b55565b6000604051808303816000865af19150503d80600081146144a8576040519150601f19603f3d011682016040523d82523d6000602084013e6144ad565b606091505b50915091508180156144d75750805115806144d75750808060200190518101906144d791906158fe565b613c0457600080fd5b60006144ef6020870187615363565b905060006145036040880160208901615363565b905060006145176060890160408a016158c8565b9050600061452b60808a0160608b01615363565b9050600061453b8585858561170f565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561457e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145a2919061597a565b50915091506103e8821115806145ba57506103e88111155b156145d8576040516302721e1f60e61b815260040160405180910390fd5b5050846001600160a01b03168d6001600160a01b0316146146b0576001600160a01b038516898961460a60018261587b565b8181106146195761461961588e565b90506080020160200160208101906146319190615363565b6001600160a01b031614614658576040516309d41c6760e31b815260040160405180910390fd5b6146b08d8d8c608001358c8c808060200260200160405190810160405280939291908181526020016000905b82821015612004576146a160808302860136819003810190615849565b81526020019060010190614684565b836001600160a01b03168d6001600160a01b031614614786576001600160a01b03841687876146e060018261587b565b8181106146ef576146ef61588e565b90506080020160200160208101906147079190615363565b6001600160a01b03161461472e576040516332b2410360e21b815260040160405180910390fd5b6147868d8c8c60a001358a8a808060200260200160405190810160405280939291908181526020016000905b828210156120045761477760808302860136819003810190615849565b8152602001906001019061475a565b50505050505050505050505050565b60006147a46020830183615363565b905060006147b86040840160208501615363565b905060006147cc60608501604086016158c8565b905060006147e06080860160608701615363565b905060006147f08585858561170f565b6040516370a0823160e01b815230600482015290915060009081906148e39088908890889088906001600160a01b038516906370a0823190602401602060405180830381865afa158015614848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061486c91906158e5565b6040516370a0823160e01b81523060048201526001600160a01b038d16906370a0823190602401602060405180830381865afa1580156148b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148d491906158e5565b8e60c001358f60e00135614bad565b915091506148f28784846143f8565b610c638684836143f8565b8015806149775750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614951573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061497591906158e5565b155b6149e75760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084015b60405180910390fd5b6040516001600160a01b0383166024820152604481018290526139a690849063095ea7b360e01b906064016133ba565b6000614a6c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cbc9092919063ffffffff16565b8051909150156139a65780806020019051810190614a8a91906158fe565b6139a65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016149de565b6040516001600160a01b0383166024820152604481018290526139a690849063a9059cbb60e01b906064016133ba565b600080608083901c15614b2e57608092831c92015b604083901c15614b4057604092831c92015b602083901c15614b5257602092831c92015b601083901c15614b6457601092831c92015b600883901c15614b7657600892831c92015b600483901c15614b8857600492831c92015b600283901c15614b9a57600292831c92015b600183901c156143f25760010192915050565b60008083861015614bd157604051636e35977960e11b815260040160405180910390fd5b82851015614bf25760405163acee051360e01b815260040160405180910390fd5b600080614c018c8c8c8c611aa8565b91509150816000148015614c13575080155b15614c2357879350869250614cad565b6000614c30898484614375565b9050878111614c655785811015614c5a57604051630d32418960e21b815260040160405180910390fd5b889450925082614cab565b6000614c72898486614375565b905089811115614c8457614c8461591b565b87811015614ca5576040516323d9bb0560e21b815260040160405180910390fd5b94508793505b505b50509850989650505050505050565b60606143d6848460008585600080866001600160a01b03168587604051614ce39190615b55565b60006040518083038185875af1925050503d8060008114614d20576040519150601f19603f3d011682016040523d82523d6000602084013e614d25565b606091505b5091509150614d3687838387614d41565b979650505050505050565b60608315614db0578251600003614da9576001600160a01b0385163b614da95760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016149de565b50816143d6565b6143d68383815115614dc55781518083602001fd5b8060405162461bcd60e51b81526004016149de9190615bd4565b6001600160a01b038116811461333f57600080fd5b8035614dff81614ddf565b919050565b801515811461333f57600080fd5b60008083601f840112614e2457600080fd5b5081356001600160401b03811115614e3b57600080fd5b6020830191508360208260071b85010111156111e257600080fd5b6000806000806000806000806000806101008b8d031215614e7657600080fd5b8a35614e8181614ddf565b995060208b0135614e9181614ddf565b985060408b0135614ea181614e04565b975060608b0135614eb181614ddf565b965060808b0135955060a08b0135945060c08b01356001600160401b0380821115614edb57600080fd5b614ee78e838f01614e12565b909650945060e08d0135915080821115614f0057600080fd5b50614f0d8d828e01614e12565b915080935050809150509295989b9194979a5092959850565b600080600080600080600080610100898b031215614f4357600080fd5b8835614f4e81614ddf565b97506020890135614f5e81614ddf565b96506040890135614f6e81614e04565b9550606089013594506080890135935060a0890135925060c0890135614f9381614ddf565b8092505060e089013590509295985092959890939650565b60008060008060008060a08789031215614fc457600080fd5b863595506020870135945060408701356001600160401b03811115614fe857600080fd5b614ff489828a01614e12565b909550935050606087013561500881614ddf565b80925050608087013590509295509295509295565b60008060008060006080868803121561503557600080fd5b8535945060208601356001600160401b0381111561505257600080fd5b61505e88828901614e12565b909550935050604086013561507281614ddf565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156150c1576150c1615083565b604052919050565b60006001600160401b038211156150e2576150e2615083565b5060051b60200190565b60008060008060006080868803121561510457600080fd5b85356001600160401b038082111561511b57600080fd5b818801915088601f83011261512f57600080fd5b8135602061514461513f836150c9565b615099565b82815260059290921b8401810191818101908c84111561516357600080fd5b948201945b8386101561518157853582529482019490820190615168565b9950508901359250508082111561519757600080fd5b506151a488828901614e12565b9095509350615072905060408701614df4565b6020808252825182820181905260009190848201906040850190845b818110156151ef578351835292840192918401916001016151d3565b50909695505050505050565b6000806040838503121561520e57600080fd5b823561521981614ddf565b9150602083013561522981614ddf565b809150509250929050565b60006080828403121561524657600080fd5b604051608081018181106001600160401b038211171561526857615268615083565b604052905080823561527981614ddf565b8152602083013561528981614ddf565b6020820152604083013561529c81614e04565b604082015260608301356152af81614ddf565b6060919091015292915050565b600080604083850312156152cf57600080fd5b823591506020808401356001600160401b038111156152ed57600080fd5b8401601f810186136152fe57600080fd5b803561530c61513f826150c9565b81815260079190911b8201830190838101908883111561532b57600080fd5b928401925b82841015615354576153428985615234565b82528482019150608084019350615330565b80955050505050509250929050565b60006020828403121561537557600080fd5b813561436e81614ddf565b60008060008060008060008060006101208a8c03121561539f57600080fd5b89356153aa81614ddf565b985060208a01356153ba81614ddf565b975060408a01356153ca81614e04565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356153f681614ddf565b809250506101008a013590509295985092959850929598565b600080600080600080600080600060e08a8c03121561542d57600080fd5b893561543881614ddf565b985060208a013561544881614ddf565b975060408a013561545881614e04565b965060608a013561546881614ddf565b955060808a0135945060a08a01356001600160401b038082111561548b57600080fd5b6154978d838e01614e12565b909650945060c08c01359150808211156154b057600080fd5b506154bd8c828d01614e12565b915080935050809150509295985092959850929598565b600080600080608085870312156154ea57600080fd5b84356154f581614ddf565b9350602085013561550581614ddf565b9250604085013561551581614e04565b9150606085013561552581614ddf565b939692955090935050565b6000610100828403121561554357600080fd5b50919050565b6000806000806000806000610180888a03121561556557600080fd5b873561557081614ddf565b9650602088013595506155868960408a01615530565b94506101408801356001600160401b03808211156155a357600080fd5b6155af8b838c01614e12565b90965094506101608a01359150808211156155c957600080fd5b506155d68a828b01614e12565b989b979a50959850939692959293505050565b600080600080600080600060e0888a03121561560457600080fd5b873561560f81614ddf565b9650602088013561561f81614e04565b955060408801359450606088013593506080880135925060a088013561564481614ddf565b8092505060c0880135905092959891949750929550565b600080600080600060a0868803121561567357600080fd5b853561567e81614ddf565b9450602086013561568e81614ddf565b9350604086013561569e81614e04565b925060608601356156ae81614ddf565b949793965091946080013592915050565b60008060008060008060c087890312156156d857600080fd5b86356156e381614ddf565b955060208701356156f381614ddf565b9450604087013561570381614e04565b9350606087013561571381614ddf565b9598949750929560808101359460a0909101359350915050565b60008060006060848603121561574257600080fd5b833561574d81614ddf565b9250602084013561575d81614ddf565b9150604084013561576d81614ddf565b809150509250925092565b6000806000806000806000806000806101e08b8d03121561579857600080fd5b8a356157a381614ddf565b995060208b0135985060408b013597506157c08c60608d01615530565b96506101608b01356001600160401b03808211156157dd57600080fd5b6157e98e838f01614e12565b90985096506101808d013591508082111561580357600080fd5b506158108d828e01614e12565b9095509350506101a08b013561582581614ddf565b91506101c08b013561583681614e04565b809150509295989b9194979a5092959850565b60006080828403121561585b57600080fd5b6143ef8383615234565b634e487b7160e01b600052601160045260246000fd5b818103818111156143f2576143f2615865565b634e487b7160e01b600052603260045260246000fd5b600080604083850312156158b757600080fd5b505080516020909101519092909150565b6000602082840312156158da57600080fd5b813561436e81614e04565b6000602082840312156158f757600080fd5b5051919050565b60006020828403121561591057600080fd5b815161436e81614e04565b634e487b7160e01b600052600160045260246000fd5b808201808211156143f2576143f2615865565b60006001820161595657615956615865565b5060010190565b60006020828403121561596f57600080fd5b815161436e81614ddf565b60008060006060848603121561598f57600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b039384168152919092166020820152901515604082015260600190565b80820281158282048414176143f2576143f2615865565b634e487b7160e01b600052601260045260246000fd5b600082615a1657634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615a2d57600080fd5b815160ff8116811461436e57600080fd5b600181815b80851115615a79578160001904821115615a5f57615a5f615865565b80851615615a6c57918102915b93841c9390800290615a43565b509250929050565b600082615a90575060016143f2565b81615a9d575060006143f2565b8160018114615ab35760028114615abd57615ad9565b60019150506143f2565b60ff841115615ace57615ace615865565b50506001821b6143f2565b5060208310610133831016604e8410600b8410161715615afc575081810a6143f2565b615b068383615a3e565b8060001904821115615b1a57615b1a615865565b029392505050565b60006143ef60ff841683615a81565b60005b83811015615b4c578181015183820152602001615b34565b50506000910152565b60008251615b67818460208701615b31565b9190910192915050565b60008151808452615b89816020860160208601615b31565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b0383166040820152608060608201526000615bca6080830184615b71565b9695505050505050565b6020815260006143ef6020830184615b7156fea2646970667358221220b68b2dd239bbcf1a487caca8c68abd0aa1b05af6b08469ed0ff93d5dde3bd1e664736f6c6343000813003300000000000000000000000015e62707fca7352fbe35f51a8d6b0f8066a05dcc0000000000000000000000005c3f18f06cc09ca1910767a34a20f771039e37c0000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a50000000000000000000000004200000000000000000000000000000000000006

Deployed Bytecode

0x6080604052600436106101c65760003560e01c8063874029d9116100f7578063c92de3ec11610095578063d7b0e0a511610064578063d7b0e0a514610643578063f5ba53c714610663578063fb49bafd14610691578063fe411f14146106a457600080fd5b8063c92de3ec146105af578063cac88ea9146105cf578063ce700c29146105ef578063d4b6846d1461060f57600080fd5b8063903638a4116100d1578063903638a414610549578063a81b91591461055c578063b7e0d4c01461057c578063c6b7f1b61461058f57600080fd5b8063874029d9146104e957806388cd821e146105095780638c0037dc1461052957600080fd5b806342cb1fbc116101645780635509a1ac1161013e5780635509a1ac14610411578063572b6c05146104315780635a47ddc31461048e5780637539d413146104c957600080fd5b806342cb1fbc1461037557806346c96aac1461039d578063544caa56146103d157600080fd5b80633bf0c9fb116101a05780633bf0c9fb146102b55780633da5acba146103015780633fc8cef3146103145780634111d5971461034857600080fd5b806307db50fa1461021b5780630dede6c41461026057806312bc3aca1461029557600080fd5b3661021657336001600160a01b037f00000000000000000000000042000000000000000000000000000000000000061614610214576040516301f180c960e01b815260040160405180910390fd5b005b600080fd5b34801561022757600080fd5b5061023b610236366004614e56565b6106c4565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561026c57600080fd5b5061028061027b366004614f26565b610806565b60408051928352602083019190915201610257565b3480156102a157600080fd5b506102146102b0366004614fab565b61095f565b3480156102c157600080fd5b506102e97f0000000000000000000000005c3f18f06cc09ca1910767a34a20f771039e37c081565b6040516001600160a01b039091168152602001610257565b61021461030f36600461501d565b610c6d565b34801561032057600080fd5b506102e97f000000000000000000000000420000000000000000000000000000000000000681565b34801561035457600080fd5b506103686103633660046150ec565b610ffe565b60405161025791906151b7565b34801561038157600080fd5b506102e973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b3480156103a957600080fd5b506102e97f00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a581565b3480156103dd57600080fd5b506103f16103ec3660046151fb565b61115e565b604080516001600160a01b03938416815292909116602083015201610257565b34801561041d57600080fd5b5061036861042c3660046152bc565b6111e9565b34801561043d57600080fd5b5061047e61044c366004615363565b7f00000000000000000000000015e62707fca7352fbe35f51a8d6b0f8066a05dcc6001600160a01b0390811691161490565b6040519015158152602001610257565b34801561049a57600080fd5b506104ae6104a9366004615380565b6114de565b60408051938452602084019290925290820152606001610257565b3480156104d557600080fd5b5061023b6104e436600461540f565b6115d6565b3480156104f557600080fd5b506102e96105043660046154d4565b61170f565b34801561051557600080fd5b50610214610524366004614fab565b611927565b34801561053557600080fd5b506102806105443660046154d4565b611aa8565b61036861055736600461501d565b611b62565b34801561056857600080fd5b50610214610577366004615549565b611e43565b6104ae61058a3660046155e9565b612164565b34801561059b57600080fd5b506103686105aa366004614fab565b6123b6565b3480156105bb57600080fd5b506102806105ca36600461565b565b61267d565b3480156105db57600080fd5b506103686105ea366004614fab565b6127c6565b3480156105fb57600080fd5b506104ae61060a3660046156bf565b6128d5565b34801561061b57600080fd5b506102e97f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da81565b34801561064f57600080fd5b5061028061065e3660046155e9565b612ab7565b34801561066f57600080fd5b5061068361067e36600461572d565b612b95565b604051908152602001610257565b61068361069f366004615778565b612e09565b3480156106b057600080fd5b506106836106bf3660046155e9565b6131d9565b8585600080606087156107595761072d8b8a8a808060200260200160405190810160405280939291908181526020016000905b828210156107235761071460808302860136819003810190615849565b815260200190600101906106f7565b50505050506111e9565b9050806001825161073e919061587b565b8151811061074e5761074e61588e565b602002602001015194505b85156107dd576107b18a8888808060200260200160405190810160405280939291908181526020016000905b82821015610723576107a260808302860136819003810190615849565b81526020019060010190610785565b905080600182516107c2919061587b565b815181106107d2576107d261588e565b602002602001015193505b6107eb8f8f8f8f89896128d5565b508093508194505050509a509a509a509a9650505050505050565b600080826108138161331e565b60006108418c8c8c7f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da61170f565b905061086061084e613342565b6001600160a01b03831690838c613386565b60405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af11580156108ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d091906158a4565b9150915060006108e08f8f61115e565b509050806001600160a01b03168f6001600160a01b031614610903578183610906565b82825b90975095508a87101561092c576040516323d9bb0560e21b815260040160405180910390fd5b8986101561094d57604051630d32418960e21b815260040160405180910390fd5b50505050509850989650505050505050565b806109698161331e565b6001600160a01b037f00000000000000000000000042000000000000000000000000000000000000061685856109a060018261587b565b8181106109af576109af61588e565b90506080020160200160208101906109c79190615363565b6001600160a01b0316146109ee576040516320db826760e01b815260040160405180910390fd5b610ad585856000818110610a0457610a0461588e565b610a1a9260206080909202019081019150615363565b610a22613342565b610acf88886000818110610a3857610a3861588e565b610a4e9260206080909202019081019150615363565b89896000818110610a6157610a6161588e565b9050608002016020016020810190610a799190615363565b8a8a6000818110610a8c57610a8c61588e565b9050608002016040016020810190610aa491906158c8565b8b8b6000818110610ab757610ab761588e565b90506080020160600160208101906105049190615363565b8a6133f7565b610b318585808060200260200160405190810160405280939291908181526020016000905b82821015610b2657610b1760808302860136819003810190615849565b81526020019060010190610afa565b5050505050306134ef565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316906370a0823190602401602060405180830381865afa158015610b98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbc91906158e5565b905086811015610bdf576040516342301c2360e01b815260040160405180910390fd5b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b50505050610c638482613918565b5050505050505050565b80610c778161331e565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031685856000818110610cb457610cb461588e565b610cca9260206080909202019081019150615363565b6001600160a01b031614610cf1576040516320db826760e01b815260040160405180910390fd5b60003490507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d5157600080fd5b505af1158015610d65573d6000803e3d6000fd5b50505050507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663a9059cbb610daf88886000818110610a3857610a3861588e565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610dfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2091906158fe565b610e2c57610e2c61591b565b6000610e3960018761587b565b90506000878783818110610e4f57610e4f61588e565b9050608002016020016020810190610e679190615363565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa158015610eaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed391906158e5565b9050610f318888808060200260200160405190810160405280939291908181526020016000905b82821015610f2657610f1760808302860136819003810190615849565b81526020019060010190610efa565b5050505050876134ef565b8881898985818110610f4557610f4561588e565b9050608002016020016020810190610f5d9190615363565b6040516370a0823160e01b81526001600160a01b038a8116600483015291909116906370a08231906024015b602060405180830381865afa158015610fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fca91906158e5565b610fd4919061587b565b1015610ff3576040516342301c2360e01b815260040160405180910390fd5b505050505050505050565b60608161100a8161331e565b6110f3868660008181106110205761102061588e565b6110369260206080909202019081019150615363565b61103e613342565b6110d3898960008181106110545761105461588e565b61106a9260206080909202019081019150615363565b8a8a600081811061107d5761107d61588e565b90506080020160200160208101906110959190615363565b8b8b60008181106110a8576110a861588e565b90506080020160400160208101906110c091906158c8565b8c8c6000818110610ab757610ab761588e565b8a6000815181106110e6576110e661588e565b60200260200101516133f7565b611150878787808060200260200160405190810160405280939291908181526020016000905b828210156111455761113660808302860136819003810190615849565b81526020019060010190611119565b5050505050866139ab565b8691505b5095945050505050565b600080826001600160a01b0316846001600160a01b03160361119357604051633295f3fd60e21b815260040160405180910390fd5b826001600160a01b0316846001600160a01b0316106111b35782846111b6565b83835b90925090506001600160a01b0382166111e25760405163d92e233d60e01b815260040160405180910390fd5b9250929050565b606060018251101561120e576040516320db826760e01b815260040160405180910390fd5b815161121b906001615931565b6001600160401b0381111561123257611232615083565b60405190808252806020026020018201604052801561125b578160200160208202803683370190505b50905082816000815181106112725761127261588e565b6020908102919091010152815160005b818110156114d6576000806001600160a01b03168583815181106112a8576112a861588e565b6020026020010151606001516001600160a01b0316146112e5578482815181106112d4576112d461588e565b602002602001015160600151611307565b7f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da5b9050600061136e8684815181106113205761132061588e565b60200260200101516000015187858151811061133e5761133e61588e565b60200260200101516020015188868151811061135c5761135c61588e565b6020026020010151604001518561170f565b604051635b16ebb760e01b81526001600160a01b03808316600483015291925090831690635b16ebb790602401602060405180830381865afa1580156113b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113dc91906158fe565b156114c157806001600160a01b031663f140a35a8685815181106114025761140261588e565b602002602001015188868151811061141c5761141c61588e565b6020026020010151600001516040518363ffffffff1660e01b81526004016114579291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015611474573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149891906158e5565b856114a4856001615931565b815181106114b4576114b461588e565b6020026020010181815250505b505080806114ce90615944565b915050611282565b505092915050565b6000806000836114ed8161331e565b6114fc8d8d8d8d8d8d8d613c0b565b9094509250600061152f8e8e8e7f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da61170f565b90506115448e61153d613342565b83886133f7565b6115578d611550613342565b83876133f7565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561159f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c391906158e5565b9250505099509950999650505050505050565b6000806000806115e98d8d8d8d8d61267d565b90945092508391508290506060871561167a5761164e838a8a808060200260200160405190810160405280939291908181526020016000905b828210156107235761163f60808302860136819003810190615849565b81526020019060010190611622565b9050806001825161165f919061587b565b8151811061166f5761166f61588e565b602002602001015194505b85156116fe576116d2828888808060200260200160405190810160405280939291908181526020016000905b82821015610723576116c360808302860136819003810190615849565b815260200190600101906116a6565b905080600182516116e3919061587b565b815181106116f3576116f361588e565b602002602001015193505b509950995099509995505050505050565b60007f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da816001600160a01b03841615611748578361174a565b815b60405163d1ea0a1d60e01b81526001600160a01b0380831660048301529192507f0000000000000000000000005c3f18f06cc09ca1910767a34a20f771039e37c09091169063d1ea0a1d90602401602060405180830381865afa1580156117b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d991906158fe565b6117f657604051634d39d5a360e11b815260040160405180910390fd5b600080611803898961115e565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015289151560f81b60488201529193509150600090604901604051602081830303815290604052805190602001209050611919846001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611898573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118bc919061595d565b604051603881018790526f5af43d82803e903d91602b57fd5bf3ff60248201526014810191909152733d602d80600a3d3981f3363d3d373d3d3d363d738152605881018390526037600c8201206078820152605560439091012090565b9a9950505050505050505050565b806119318161331e565b61194785856000818110610a0457610a0461588e565b600061195460018661587b565b9050600086868381811061196a5761196a61588e565b90506080020160200160208101906119829190615363565b6040516370a0823160e01b81526001600160a01b03878116600483015291909116906370a0823190602401602060405180830381865afa1580156119ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ee91906158e5565b9050611a4c8787808060200260200160405190810160405280939291908181526020016000905b82821015611a4157611a3260808302860136819003810190615849565b81526020019060010190611a15565b5050505050866134ef565b8781888885818110611a6057611a6061588e565b9050608002016020016020810190611a789190615363565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401610f89565b6000806000611ab7878761115e565b509050600080611ac98989898961170f565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b2a919061597a565b5091509150826001600160a01b0316896001600160a01b031614611b4f578082611b52565b81815b909a909950975050505050505050565b606081611b6e8161331e565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031686866000818110611bab57611bab61588e565b611bc19260206080909202019081019150615363565b6001600160a01b031614611be8576040516320db826760e01b815260040160405180910390fd5b611c3a348787808060200260200160405190810160405280939291908181526020016000905b8282101561072357611c2b60808302860136819003810190615849565b81526020019060010190611c0e565b9150868260018451611c4c919061587b565b81518110611c5c57611c5c61588e565b60200260200101511015611c83576040516342301c2360e01b815260040160405180910390fd5b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db083600081518110611cc557611cc561588e565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cf857600080fd5b505af1158015611d0c573d6000803e3d6000fd5b50505050507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663a9059cbb611d5688886000818110610a3857610a3861588e565b84600081518110611d6957611d6961588e565b60200260200101516040518363ffffffff1660e01b8152600401611da29291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015611dc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de591906158fe565b611df157611df161591b565b611154828787808060200260200160405190810160405280939291908181526020016000905b8282101561114557611e3460808302860136819003810190615849565b81526020019060010190611e17565b6000611e526020870187615363565b90506000611e666040880160208901615363565b905060006001600160a01b038a1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611e945789611eb6565b7f00000000000000000000000042000000000000000000000000000000000000065b9050611ec28989613e74565b6000816001600160a01b0316846001600160a01b03161461200e576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015611f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4591906158e5565b90506001600160a01b0382168888611f5e60018261587b565b818110611f6d57611f6d61588e565b9050608002016020016020810190611f859190615363565b6001600160a01b031614611fac576040516309d41c6760e31b815260040160405180910390fd5b61200e84828b608001358b8b808060200260200160405190810160405280939291908181526020016000905b8282101561200457611ff560808302860136819003810190615849565b81526020019060010190611fd8565b5050505050613fd9565b816001600160a01b0316836001600160a01b03161461214e576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa15801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f91906158e5565b90506001600160a01b03821686866120a860018261587b565b8181106120b7576120b761588e565b90506080020160200160208101906120cf9190615363565b6001600160a01b0316146120f6576040516332b2410360e21b815260040160405180910390fd5b61214e83828b60a001358989808060200260200160405190810160405280939291908181526020016000905b828210156120045761213f60808302860136819003810190615849565b81526020019060010190612122565b6121578b6140bb565b5050505050505050505050565b6000806000836121738161331e565b6121a28b7f00000000000000000000000042000000000000000000000000000000000000068c8c348d8d613c0b565b909450925060006121f58c7f00000000000000000000000042000000000000000000000000000000000000068d7f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da61170f565b90506122038c61153d613342565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561225e57600080fd5b505af1158015612272573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000420000000000000000000000000000000000000616935063a9059cbb925060440190506020604051808303816000875af11580156122e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230b91906158fe565b6123175761231761591b565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561235f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238391906158e5565b9250833411156123a7576123a7612398613342565b6123a2863461587b565b613918565b50509750975097945050505050565b6060816123c28161331e565b6001600160a01b037f00000000000000000000000042000000000000000000000000000000000000061686866123f960018261587b565b8181106124085761240861588e565b90506080020160200160208101906124209190615363565b6001600160a01b031614612447576040516320db826760e01b815260040160405180910390fd5b612499888787808060200260200160405190810160405280939291908181526020016000905b828210156107235761248a60808302860136819003810190615849565b8152602001906001019061246d565b91508682600184516124ab919061587b565b815181106124bb576124bb61588e565b602002602001015110156124e2576040516342301c2360e01b815260040160405180910390fd5b61253f868660008181106124f8576124f861588e565b61250e9260206080909202019081019150615363565b612516613342565b61252c898960008181106110545761105461588e565b856000815181106110e6576110e661588e565b61259c828787808060200260200160405190810160405280939291908181526020016000905b828210156125915761258260808302860136819003810190615849565b81526020019060010190612565565b5050505050306139ab565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316632e1a7d4d83600185516125da919061587b565b815181106125ea576125ea61588e565b60200260200101516040518263ffffffff1660e01b815260040161261091815260200190565b600060405180830381600087803b15801561262a57600080fd5b505af115801561263e573d6000803e3d6000fd5b50505050612672848360018551612655919061587b565b815181106126655761266561588e565b6020026020010151613918565b509695505050505050565b6000806000846001600160a01b03166379bc57d58989896040518463ffffffff1660e01b81526004016126b2939291906159a8565b602060405180830381865afa1580156126cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f3919061595d565b90506001600160a01b0381166127105760008092509250506127bc565b60008061271f8a8a8a8a611aa8565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612763573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061278791906158e5565b90508061279484896159cc565b61279e91906159f9565b9550806127ab83896159cc565b6127b591906159f9565b9450505050505b9550959350505050565b6060816127d28161331e565b612824888787808060200260200160405190810160405280939291908181526020016000905b828210156107235761281560808302860136819003810190615849565b815260200190600101906127f8565b9150868260018451612836919061587b565b815181106128465761284661588e565b6020026020010151101561286d576040516342301c2360e01b815260040160405180910390fd5b612883868660008181106124f8576124f861588e565b612672828787808060200260200160405190810160405280939291908181526020016000905b82821015611145576128c660808302860136819003810190615849565b815260200190600101906128a9565b600080600080866001600160a01b03166379bc57d58b8b8b6040518463ffffffff1660e01b815260040161290b939291906159a8565b602060405180830381865afa158015612928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061294c919061595d565b9050600080806001600160a01b038416156129d757836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561299f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c391906158e5565b90506129d18d8d8d8d611aa8565b90935091505b821580156129e3575081155b15612a14578896508795506103e8612a036129fe888a6159cc565b614286565b612a0d919061587b565b9450612aa7565b6000612a218a8585614375565b9050888111612a6957899750955085612a6284612a3e848b6159cc565b612a4891906159f9565b84612a53858b6159cc565b612a5d91906159f9565b6143de565b9550612aa5565b6000612a768a8587614375565b9850899750889050612aa185612a8c85846159cc565b612a9691906159f9565b85612a53868c6159cc565b9650505b505b5050505096509650969350505050565b60008082612ac48161331e565b612af48a7f00000000000000000000000042000000000000000000000000000000000000068b8b8b8b308b610806565b9093509150612b048a86856143f8565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612b6657600080fd5b505af1158015612b7a573d6000803e3d6000fd5b50505050612b888583613918565b5097509795505050505050565b600080612ba5858560018661170f565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612be7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0b9190615a1b565b612c1690600a615b22565b90506000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7c9190615a1b565b612c8790600a615b22565b6040516378a051ad60e11b8152600481018490526001600160a01b03898116602483015291925083916000919086169063f140a35a90604401602060405180830381865afa158015612cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0191906158e5565b9050600080612d158b8b60018c88886128d5565b50909250905085612d2e83670de0b6b3a76400006159cc565b612d3891906159f9565b915084612d4d82670de0b6b3a76400006159cc565b612d5791906159f9565b905084612d6c84670de0b6b3a76400006159cc565b612d7691906159f9565b925085612d8b85670de0b6b3a76400006159cc565b612d9591906159f9565b9350808285612dac86670de0b6b3a76400006159cc565b612db691906159f9565b612dc091906159cc565b612dca91906159f9565b9750612dde88670de0b6b3a7640000615931565b612df085670de0b6b3a76400006159cc565b612dfa91906159f9565b9b9a5050505050505050505050565b600080612e168a8c615931565b90508b3473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601612efb57808314612e5f57604051633851fdc960e11b815260040160405180910390fd5b7f000000000000000000000000420000000000000000000000000000000000000691507f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015612edd57600080fd5b505af1158015612ef1573d6000803e3d6000fd5b5050505050612f2d565b8015612f1a5760405163ae6d566f60e01b815260040160405180910390fd5b612f2d82612f26613342565b30866133f7565b612f3d828e8e8e8e8e8e8e6144e0565b612f468b614795565b6000612f91612f5860208e018e615363565b8d6020016020810190612f6b9190615363565b8e6040016020810190612f7e91906158c8565b8f60600160208101906105049190615363565b90508515613127576040516335313c2160e11b81523060048201526001600160a01b03821690636a627842906024016020604051808303816000875af1158015612fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061300391906158e5565b60405163b9a09fd560e01b81526001600160a01b0383811660048301529196506000917f00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a5169063b9a09fd590602401602060405180830381865afa15801561306f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613093919061595d565b90506130a96001600160a01b03831682886148fd565b604051636e553f6560e01b8152600481018790526001600160a01b038981166024830152821690636e553f6590604401600060405180830381600087803b1580156130f357600080fd5b505af1158015613107573d6000803e3d6000fd5b50613121925050506001600160a01b0383168260006148fd565b50613196565b6040516335313c2160e11b81526001600160a01b038881166004830152821690636a627842906024016020604051808303816000875af115801561316f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319391906158e5565b94505b61319f8f6140bb565b6131b46131af60208e018e615363565b6140bb565b6131c76131af60408e0160208f01615363565b505050509a9950505050505050505050565b6000816131e58161331e565b613215897f00000000000000000000000042000000000000000000000000000000000000068a8a8a8a308a610806565b6040516370a0823160e01b815230600482015290935061328e91508a9086906001600160a01b038316906370a0823190602401602060405180830381865afa158015613265573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328991906158e5565b6143f8565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156132f057600080fd5b505af1158015613304573d6000803e3d6000fd5b505050506133128483613918565b50979650505050505050565b4281101561333f57604051630407b05b60e31b815260040160405180910390fd5b50565b60007f00000000000000000000000015e62707fca7352fbe35f51a8d6b0f8066a05dcc6001600160a01b03163303613381575060131936013560601c90565b503390565b6040516001600160a01b03808516602483015283166044820152606481018290526133f19085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a17565b50505050565b6000846001600160a01b03163b1161340e57600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916134729190615b55565b6000604051808303816000865af19150503d80600081146134af576040519150601f19603f3d011682016040523d82523d6000602084013e6134b4565b606091505b50915091508180156134de5750805115806134de5750808060200190518101906134de91906158fe565b6134e757600080fd5b505050505050565b815160005b818110156133f15760006135428583815181106135135761351361588e565b6020026020010151600001518684815181106135315761353161588e565b60200260200101516020015161115e565b50905060006135c786848151811061355c5761355c61588e565b60200260200101516000015187858151811061357a5761357a61588e565b6020026020010151602001518886815181106135985761359861588e565b6020026020010151604001518987815181106135b6576135b661588e565b60200260200101516060015161170f565b9050600080600061364e8987815181106135e3576135e361588e565b6020026020010151600001518a88815181106136015761360161588e565b6020026020010151602001518b898151811061361f5761361f61588e565b6020026020010151604001518c8a8151811061363d5761363d61588e565b602002602001015160600151611aa8565b509050808987815181106136645761366461588e565b6020908102919091010151516040516370a0823160e01b81526001600160a01b038781166004830152909116906370a0823190602401602060405180830381865afa1580156136b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136db91906158e5565b6136e5919061587b565b925050826001600160a01b031663f140a35a838a888151811061370a5761370a61588e565b6020026020010151600001516040518363ffffffff1660e01b81526004016137459291909182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613762573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378691906158e5565b9050600080856001600160a01b03168a88815181106137a7576137a761588e565b6020026020010151600001516001600160a01b0316146137c9578260006137cd565b6000835b91509150600060018b516137e1919061587b565b88106137ed578961388a565b61388a8b6137fc8a6001615931565b8151811061380c5761380c61588e565b6020026020010151600001518c8a60016138269190615931565b815181106138365761383661588e565b6020026020010151602001518d8b60016138509190615931565b815181106138605761386061588e565b6020026020010151604001518e8c600161387a9190615931565b815181106135b6576135b661588e565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f906138cc9086908690869060248101615b9d565b600060405180830381600087803b1580156138e657600080fd5b505af11580156138fa573d6000803e3d6000fd5b5050505050505050505050808061391090615944565b9150506134f4565b604080516000808252602082019092526001600160a01b0384169083906040516139429190615b55565b60006040518083038185875af1925050503d806000811461397f576040519150601f19603f3d011682016040523d82523d6000602084013e613984565b606091505b50509050806139a65760405163b12d13eb60e01b815260040160405180910390fd5b505050565b815160005b81811015613c045760006139cf8583815181106135135761351361588e565b5090506000866139e0846001615931565b815181106139f0576139f061588e565b60200260200101519050600080836001600160a01b0316888681518110613a1957613a1961588e565b6020026020010151600001516001600160a01b031614613a3b57826000613a3f565b6000835b91509150600060018951613a53919061587b565b8610613a5f5787613aec565b613aec89613a6e886001615931565b81518110613a7e57613a7e61588e565b6020026020010151600001518a886001613a989190615931565b81518110613aa857613aa861588e565b6020026020010151602001518b896001613ac29190615931565b81518110613ad257613ad261588e565b6020026020010151604001518c8a600161387a9190615931565b9050613b5d898781518110613b0357613b0361588e565b6020026020010151600001518a8881518110613b2157613b2161588e565b6020026020010151602001518b8981518110613b3f57613b3f61588e565b6020026020010151604001518c8a815181106135b6576135b661588e565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613b9a576020820181803683370190505b506040518563ffffffff1660e01b8152600401613bba9493929190615b9d565b600060405180830381600087803b158015613bd457600080fd5b505af1158015613be8573d6000803e3d6000fd5b5050505050505050508080613bfc90615944565b9150506139b0565b5050505050565b60008083861015613c2f57604051636e35977960e11b815260040160405180910390fd5b82851015613c505760405163acee051360e01b815260040160405180910390fd5b6040516379bc57d560e01b81526000906001600160a01b037f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da16906379bc57d590613ca3908d908d908d906004016159a8565b602060405180830381865afa158015613cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce4919061595d565b90506001600160a01b038116613d8a576040516301b5fcad60e51b81526001600160a01b037f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da16906336bf95a090613d44908d908d908d906004016159a8565b6020604051808303816000875af1158015613d63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d87919061595d565b90505b600080613db98c8c8c7f000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da611aa8565b91509150816000148015613dcb575080155b15613ddb57889450879350613e65565b6000613de88a8484614375565b9050888111613e1d5786811015613e1257604051630d32418960e21b815260040160405180910390fd5b899550935083613e63565b6000613e2a8a8486614375565b90508a811115613e3c57613e3c61591b565b88811015613e5d576040516323d9bb0560e21b815260040160405180910390fd5b95508894505b505b50505097509795505050505050565b6000613e836020830183615363565b90506000613e976040840160208501615363565b90506000613ec08383613eb060608801604089016158c8565b6105046080890160608a01615363565b9050613ed76001600160a01b038216338388613386565b6000613ee3848461115e565b5060405163226bf2d160e21b815230600482015290915060009081906001600160a01b038516906389afcb449060240160408051808303816000875af1158015613f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f5591906158a4565b91509150600080846001600160a01b0316886001600160a01b031614613f7c578284613f7f565b83835b915091508860c00135821015613fa8576040516323d9bb0560e21b815260040160405180910390fd5b8860e00135811015613fcd57604051630d32418960e21b815260040160405180910390fd5b50505050505050505050565b6000613fe584836111e9565b9050828160018351613ff7919061587b565b815181106140075761400761588e565b6020026020010151101561402e576040516342301c2360e01b815260040160405180910390fd5b60006140a3836000815181106140465761404661588e565b602002602001015160000151846000815181106140655761406561588e565b602002602001015160200151856000815181106140845761408461588e565b602002602001015160400151866000815181106135b6576135b661588e565b90506140b08682876143f8565b6134e78284306139ab565b60006140c5613342565b9050600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601614202576040516370a0823160e01b81523060048201527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316906370a0823190602401602060405180830381865afa158015614152573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061417691906158e5565b905080156139a657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156141e057600080fd5b505af11580156141f4573d6000803e3d6000fd5b505050506139a68282613918565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015614246573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426a91906158e5565b905080156139a6576139a66001600160a01b0384168383614ae9565b60008160000361429857506000919050565b600060016142a584614b19565b901c6001901b905060018184816142be576142be6159e3565b048201901c905060018184816142d6576142d66159e3565b048201901c905060018184816142ee576142ee6159e3565b048201901c90506001818481614306576143066159e3565b048201901c9050600181848161431e5761431e6159e3565b048201901c90506001818481614336576143366159e3565b048201901c9050600181848161434e5761434e6159e3565b048201901c905061436e81828581614368576143686159e3565b046143de565b9392505050565b60008360000361439857604051632ca2f52b60e11b815260040160405180910390fd5b8215806143a3575081155b156143c15760405163bb55fd2760e01b815260040160405180910390fd5b826143cc83866159cc565b6143d691906159f9565b949350505050565b60008183106143ed57816143ef565b825b90505b92915050565b6000836001600160a01b03163b1161440f57600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161446b9190615b55565b6000604051808303816000865af19150503d80600081146144a8576040519150601f19603f3d011682016040523d82523d6000602084013e6144ad565b606091505b50915091508180156144d75750805115806144d75750808060200190518101906144d791906158fe565b613c0457600080fd5b60006144ef6020870187615363565b905060006145036040880160208901615363565b905060006145176060890160408a016158c8565b9050600061452b60808a0160608b01615363565b9050600061453b8585858561170f565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561457e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145a2919061597a565b50915091506103e8821115806145ba57506103e88111155b156145d8576040516302721e1f60e61b815260040160405180910390fd5b5050846001600160a01b03168d6001600160a01b0316146146b0576001600160a01b038516898961460a60018261587b565b8181106146195761461961588e565b90506080020160200160208101906146319190615363565b6001600160a01b031614614658576040516309d41c6760e31b815260040160405180910390fd5b6146b08d8d8c608001358c8c808060200260200160405190810160405280939291908181526020016000905b82821015612004576146a160808302860136819003810190615849565b81526020019060010190614684565b836001600160a01b03168d6001600160a01b031614614786576001600160a01b03841687876146e060018261587b565b8181106146ef576146ef61588e565b90506080020160200160208101906147079190615363565b6001600160a01b03161461472e576040516332b2410360e21b815260040160405180910390fd5b6147868d8c8c60a001358a8a808060200260200160405190810160405280939291908181526020016000905b828210156120045761477760808302860136819003810190615849565b8152602001906001019061475a565b50505050505050505050505050565b60006147a46020830183615363565b905060006147b86040840160208501615363565b905060006147cc60608501604086016158c8565b905060006147e06080860160608701615363565b905060006147f08585858561170f565b6040516370a0823160e01b815230600482015290915060009081906148e39088908890889088906001600160a01b038516906370a0823190602401602060405180830381865afa158015614848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061486c91906158e5565b6040516370a0823160e01b81523060048201526001600160a01b038d16906370a0823190602401602060405180830381865afa1580156148b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148d491906158e5565b8e60c001358f60e00135614bad565b915091506148f28784846143f8565b610c638684836143f8565b8015806149775750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614951573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061497591906158e5565b155b6149e75760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084015b60405180910390fd5b6040516001600160a01b0383166024820152604481018290526139a690849063095ea7b360e01b906064016133ba565b6000614a6c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cbc9092919063ffffffff16565b8051909150156139a65780806020019051810190614a8a91906158fe565b6139a65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016149de565b6040516001600160a01b0383166024820152604481018290526139a690849063a9059cbb60e01b906064016133ba565b600080608083901c15614b2e57608092831c92015b604083901c15614b4057604092831c92015b602083901c15614b5257602092831c92015b601083901c15614b6457601092831c92015b600883901c15614b7657600892831c92015b600483901c15614b8857600492831c92015b600283901c15614b9a57600292831c92015b600183901c156143f25760010192915050565b60008083861015614bd157604051636e35977960e11b815260040160405180910390fd5b82851015614bf25760405163acee051360e01b815260040160405180910390fd5b600080614c018c8c8c8c611aa8565b91509150816000148015614c13575080155b15614c2357879350869250614cad565b6000614c30898484614375565b9050878111614c655785811015614c5a57604051630d32418960e21b815260040160405180910390fd5b889450925082614cab565b6000614c72898486614375565b905089811115614c8457614c8461591b565b87811015614ca5576040516323d9bb0560e21b815260040160405180910390fd5b94508793505b505b50509850989650505050505050565b60606143d6848460008585600080866001600160a01b03168587604051614ce39190615b55565b60006040518083038185875af1925050503d8060008114614d20576040519150601f19603f3d011682016040523d82523d6000602084013e614d25565b606091505b5091509150614d3687838387614d41565b979650505050505050565b60608315614db0578251600003614da9576001600160a01b0385163b614da95760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016149de565b50816143d6565b6143d68383815115614dc55781518083602001fd5b8060405162461bcd60e51b81526004016149de9190615bd4565b6001600160a01b038116811461333f57600080fd5b8035614dff81614ddf565b919050565b801515811461333f57600080fd5b60008083601f840112614e2457600080fd5b5081356001600160401b03811115614e3b57600080fd5b6020830191508360208260071b85010111156111e257600080fd5b6000806000806000806000806000806101008b8d031215614e7657600080fd5b8a35614e8181614ddf565b995060208b0135614e9181614ddf565b985060408b0135614ea181614e04565b975060608b0135614eb181614ddf565b965060808b0135955060a08b0135945060c08b01356001600160401b0380821115614edb57600080fd5b614ee78e838f01614e12565b909650945060e08d0135915080821115614f0057600080fd5b50614f0d8d828e01614e12565b915080935050809150509295989b9194979a5092959850565b600080600080600080600080610100898b031215614f4357600080fd5b8835614f4e81614ddf565b97506020890135614f5e81614ddf565b96506040890135614f6e81614e04565b9550606089013594506080890135935060a0890135925060c0890135614f9381614ddf565b8092505060e089013590509295985092959890939650565b60008060008060008060a08789031215614fc457600080fd5b863595506020870135945060408701356001600160401b03811115614fe857600080fd5b614ff489828a01614e12565b909550935050606087013561500881614ddf565b80925050608087013590509295509295509295565b60008060008060006080868803121561503557600080fd5b8535945060208601356001600160401b0381111561505257600080fd5b61505e88828901614e12565b909550935050604086013561507281614ddf565b949793965091946060013592915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156150c1576150c1615083565b604052919050565b60006001600160401b038211156150e2576150e2615083565b5060051b60200190565b60008060008060006080868803121561510457600080fd5b85356001600160401b038082111561511b57600080fd5b818801915088601f83011261512f57600080fd5b8135602061514461513f836150c9565b615099565b82815260059290921b8401810191818101908c84111561516357600080fd5b948201945b8386101561518157853582529482019490820190615168565b9950508901359250508082111561519757600080fd5b506151a488828901614e12565b9095509350615072905060408701614df4565b6020808252825182820181905260009190848201906040850190845b818110156151ef578351835292840192918401916001016151d3565b50909695505050505050565b6000806040838503121561520e57600080fd5b823561521981614ddf565b9150602083013561522981614ddf565b809150509250929050565b60006080828403121561524657600080fd5b604051608081018181106001600160401b038211171561526857615268615083565b604052905080823561527981614ddf565b8152602083013561528981614ddf565b6020820152604083013561529c81614e04565b604082015260608301356152af81614ddf565b6060919091015292915050565b600080604083850312156152cf57600080fd5b823591506020808401356001600160401b038111156152ed57600080fd5b8401601f810186136152fe57600080fd5b803561530c61513f826150c9565b81815260079190911b8201830190838101908883111561532b57600080fd5b928401925b82841015615354576153428985615234565b82528482019150608084019350615330565b80955050505050509250929050565b60006020828403121561537557600080fd5b813561436e81614ddf565b60008060008060008060008060006101208a8c03121561539f57600080fd5b89356153aa81614ddf565b985060208a01356153ba81614ddf565b975060408a01356153ca81614e04565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356153f681614ddf565b809250506101008a013590509295985092959850929598565b600080600080600080600080600060e08a8c03121561542d57600080fd5b893561543881614ddf565b985060208a013561544881614ddf565b975060408a013561545881614e04565b965060608a013561546881614ddf565b955060808a0135945060a08a01356001600160401b038082111561548b57600080fd5b6154978d838e01614e12565b909650945060c08c01359150808211156154b057600080fd5b506154bd8c828d01614e12565b915080935050809150509295985092959850929598565b600080600080608085870312156154ea57600080fd5b84356154f581614ddf565b9350602085013561550581614ddf565b9250604085013561551581614e04565b9150606085013561552581614ddf565b939692955090935050565b6000610100828403121561554357600080fd5b50919050565b6000806000806000806000610180888a03121561556557600080fd5b873561557081614ddf565b9650602088013595506155868960408a01615530565b94506101408801356001600160401b03808211156155a357600080fd5b6155af8b838c01614e12565b90965094506101608a01359150808211156155c957600080fd5b506155d68a828b01614e12565b989b979a50959850939692959293505050565b600080600080600080600060e0888a03121561560457600080fd5b873561560f81614ddf565b9650602088013561561f81614e04565b955060408801359450606088013593506080880135925060a088013561564481614ddf565b8092505060c0880135905092959891949750929550565b600080600080600060a0868803121561567357600080fd5b853561567e81614ddf565b9450602086013561568e81614ddf565b9350604086013561569e81614e04565b925060608601356156ae81614ddf565b949793965091946080013592915050565b60008060008060008060c087890312156156d857600080fd5b86356156e381614ddf565b955060208701356156f381614ddf565b9450604087013561570381614e04565b9350606087013561571381614ddf565b9598949750929560808101359460a0909101359350915050565b60008060006060848603121561574257600080fd5b833561574d81614ddf565b9250602084013561575d81614ddf565b9150604084013561576d81614ddf565b809150509250925092565b6000806000806000806000806000806101e08b8d03121561579857600080fd5b8a356157a381614ddf565b995060208b0135985060408b013597506157c08c60608d01615530565b96506101608b01356001600160401b03808211156157dd57600080fd5b6157e98e838f01614e12565b90985096506101808d013591508082111561580357600080fd5b506158108d828e01614e12565b9095509350506101a08b013561582581614ddf565b91506101c08b013561583681614e04565b809150509295989b9194979a5092959850565b60006080828403121561585b57600080fd5b6143ef8383615234565b634e487b7160e01b600052601160045260246000fd5b818103818111156143f2576143f2615865565b634e487b7160e01b600052603260045260246000fd5b600080604083850312156158b757600080fd5b505080516020909101519092909150565b6000602082840312156158da57600080fd5b813561436e81614e04565b6000602082840312156158f757600080fd5b5051919050565b60006020828403121561591057600080fd5b815161436e81614e04565b634e487b7160e01b600052600160045260246000fd5b808201808211156143f2576143f2615865565b60006001820161595657615956615865565b5060010190565b60006020828403121561596f57600080fd5b815161436e81614ddf565b60008060006060848603121561598f57600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b039384168152919092166020820152901515604082015260600190565b80820281158282048414176143f2576143f2615865565b634e487b7160e01b600052601260045260246000fd5b600082615a1657634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615a2d57600080fd5b815160ff8116811461436e57600080fd5b600181815b80851115615a79578160001904821115615a5f57615a5f615865565b80851615615a6c57918102915b93841c9390800290615a43565b509250929050565b600082615a90575060016143f2565b81615a9d575060006143f2565b8160018114615ab35760028114615abd57615ad9565b60019150506143f2565b60ff841115615ace57615ace615865565b50506001821b6143f2565b5060208310610133831016604e8410600b8410161715615afc575081810a6143f2565b615b068383615a3e565b8060001904821115615b1a57615b1a615865565b029392505050565b60006143ef60ff841683615a81565b60005b83811015615b4c578181015183820152602001615b34565b50506000910152565b60008251615b67818460208701615b31565b9190910192915050565b60008151808452615b89816020860160208601615b31565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b0383166040820152608060608201526000615bca6080830184615b71565b9695505050505050565b6020815260006143ef6020830184615b7156fea2646970667358221220b68b2dd239bbcf1a487caca8c68abd0aa1b05af6b08469ed0ff93d5dde3bd1e664736f6c63430008130033

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

00000000000000000000000015e62707fca7352fbe35f51a8d6b0f8066a05dcc0000000000000000000000005c3f18f06cc09ca1910767a34a20f771039e37c0000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a50000000000000000000000004200000000000000000000000000000000000006

-----Decoded View---------------
Arg [0] : _forwarder (address): 0x15e62707FCA7352fbE35F51a8D6b0F8066A05DCc
Arg [1] : _factoryRegistry (address): 0x5C3F18F06CC09CA1910767A34a20F771039E37C0
Arg [2] : _factory (address): 0x420DD381b31aEf6683db6B902084cB0FFECe40Da
Arg [3] : _voter (address): 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5
Arg [4] : _weth (address): 0x4200000000000000000000000000000000000006

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000015e62707fca7352fbe35f51a8d6b0f8066a05dcc
Arg [1] : 0000000000000000000000005c3f18f06cc09ca1910767a34a20f771039e37c0
Arg [2] : 000000000000000000000000420dd381b31aef6683db6b902084cb0ffece40da
Arg [3] : 00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a5
Arg [4] : 0000000000000000000000004200000000000000000000000000000000000006


Deployed ByteCode Sourcemap

91746:31753:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92893:10;-1:-1:-1;;;;;92915:4:0;92893:27;;92889:50;;92929:10;;-1:-1:-1;;;92929:10:0;;;;;;;;;;;92889:50;91746:31753;;;;;119089:930;;;;;;;;;;-1:-1:-1;119089:930:0;;;;;:::i;:::-;;:::i;:::-;;;;2578:25:1;;;2634:2;2619:18;;2612:34;;;;2662:18;;;2655:34;2720:2;2705:18;;2698:34;2565:3;2550:19;119089:930:0;;;;;;;;101707:803;;;;;;;;;;-1:-1:-1;101707:803:0;;;;;:::i;:::-;;:::i;:::-;;;;3863:25:1;;;3919:2;3904:18;;3897:34;;;;3836:18;101707:803:0;3689:248:1;110805:809:0;;;;;;;;;;-1:-1:-1;110805:809:0;;;;;:::i;:::-;;:::i;91860:40::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4928:32:1;;;4910:51;;4898:2;4883:18;91860:40:0;4764:203:1;109980:788:0;;;;;;:::i;:::-;;:::i;92077:27::-;;;;;;;;;;;;;;;107211:497;;;;;;;;;;-1:-1:-1;107211:497:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;92200:74::-;;;;;;;;;;;;92232:42;92200:74;;92011:30;;;;;;;;;;;;;;;92984:308;;;;;;;;;;-1:-1:-1;92984:308:0;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;9223:15:1;;;9205:34;;9275:15;;;;9270:2;9255:18;;9248:43;9140:18;92984:308:0;8993:304:1;95059:730:0;;;;;;;;;;-1:-1:-1;95059:730:0;;;;;:::i;:::-;;:::i;86638:138::-;;;;;;;;;;-1:-1:-1;86638:138:0;;;;;:::i;:::-;86751:17;-1:-1:-1;;;;;86738:30:0;;;;;;;86638:138;;;;11624:14:1;;11617:22;11599:41;;11587:2;11572:18;86638:138:0;11459:187:1;99766:840:0;;;;;;;;;;-1:-1:-1;99766:840:0;;;;;:::i;:::-;;:::i;:::-;;;;12868:25:1;;;12924:2;12909:18;;12902:34;;;;12952:18;;;12945:34;12856:2;12841:18;99766:840:0;12666:319:1;120056:889:0;;;;;;;;;;-1:-1:-1;120056:889:0;;;;;:::i;:::-;;:::i;93329:626::-;;;;;;;;;;-1:-1:-1;93329:626:0;;;;;:::i;:::-;;:::i;109193:750::-;;;;;;;;;;-1:-1:-1;109193:750:0;;;;;:::i;:::-;;:::i;94562:460::-;;;;;;;;;;-1:-1:-1;94562:460:0;;;;;:::i;:::-;;:::i;105710:642::-;;;;;;:::i;:::-;;:::i;117218:1034::-;;;;;;;;;;-1:-1:-1;117218:1034:0;;;;;:::i;:::-;;:::i;100643:990::-;;;;;;:::i;:::-;;:::i;106360:843::-;;;;;;;;;;-1:-1:-1;106360:843:0;;;;;:::i;:::-;;:::i;97366:757::-;;;;;;;;;;-1:-1:-1;97366:757:0;;;;;:::i;:::-;;:::i;105062:640::-;;;;;;;;;;-1:-1:-1;105062:640:0;;;;;:::i;:::-;;:::i;95826:1503::-;;;;;;;;;;-1:-1:-1;95826:1503:0;;;;;:::i;:::-;;:::i;91936:39::-;;;;;;;;;;;;;;;102547:691;;;;;;;;;;-1:-1:-1;102547:691:0;;;;;:::i;:::-;;:::i;121678:920::-;;;;;;;;;;-1:-1:-1;121678:920:0;;;;;:::i;:::-;;:::i;:::-;;;19508:25:1;;;19496:2;19481:18;121678:920:0;19362:177:1;111651:1527:0;;;;;;:::i;:::-;;:::i;103317:715::-;;;;;;;;;;-1:-1:-1;103317:715:0;;;;;:::i;:::-;;:::i;119089:930::-;119486:9;119522;119373:21;;119542:24;119581:18;;119577:152;;119626:33;119640:9;119651:7;;119626:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:13;:33::i;:::-;119616:43;;119690:7;119715:1;119698:7;:14;:18;;;;:::i;:::-;119690:27;;;;;;;;:::i;:::-;;;;;;;119674:43;;119577:152;119743:18;;119739:152;;119788:33;119802:9;119813:7;;119788:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;119778:43;;119852:7;119877:1;119860:7;:14;:18;;;;:::i;:::-;119852:27;;;;;;;;:::i;:::-;;;;;;;119836:43;;119739:152;119930:81;119948:6;119956;119964;119972:8;119982:13;119997;119930:17;:81::i;:::-;119901:110;;;;;;;;;119459:560;119089:930;;;;;;;;;;;;;;;:::o;101707:803::-;101978:15;101995;101959:8;92328:25;92344:8;92328:15;:25::i;:::-;102023:12:::1;102038:47;102046:6;102054;102062;102070:14;102038:7;:47::i;:::-;102023:62;;102096:60;102126:12;:10;:12::i;:::-;-1:-1:-1::0;;;;;102096:29:0;::::1;::::0;102140:4;102146:9;102096:29:::1;:60::i;:::-;102204:20;::::0;-1:-1:-1;;;102204:20:0;;-1:-1:-1;;;;;4928:32:1;;;102204:20:0::1;::::0;::::1;4910:51:1::0;102168:15:0::1;::::0;;;102204:16;::::1;::::0;::::1;::::0;4883:18:1;;102204:20:0::1;::::0;::::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;102167:57;;;;102236:14;102256:26;102267:6;102275;102256:10;:26::i;:::-;102235:47;;;102324:6;-1:-1:-1::0;;;;;102314:16:0::1;:6;-1:-1:-1::0;;;;;102314:16:0::1;;:58;;102355:7;102364;102314:58;;;102334:7;102343;102314:58;102293:79:::0;;-1:-1:-1;102293:79:0;-1:-1:-1;102387:20:0;;::::1;102383:54;;;102416:21;;-1:-1:-1::0;;;102416:21:0::1;;;;;;;;;;;102383:54;102462:10;102452:7;:20;102448:54;;;102481:21;;-1:-1:-1::0;;;102481:21:0::1;;;;;;;;;;;102448:54;102012:498;;;;101707:803:::0;;;;;;;;;;;;:::o;110805:809::-;111028:8;92328:25;92344:8;92328:15;:25::i;:::-;-1:-1:-1;;;;;111093:4:0::1;111053:45;:6:::0;;111060:17:::1;111076:1;111053:6:::0;111060:17:::1;:::i;:::-;111053:25;;;;;;;:::i;:::-;;;;;;:28;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;111053:45:0::1;;111049:71;;111107:13;;-1:-1:-1::0;;;111107:13:0::1;;;;;;;;;;;111049:71;111131:196;111163:6;;111170:1;111163:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;111163:14:0::1;:::i;:::-;111192:12;:10;:12::i;:::-;111219:74;111227:6;;111234:1;111227:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;111227:14:0::1;:::i;:::-;111243:6;;111250:1;111243:9;;;;;;;:::i;:::-;;;;;;:12;;;;;;;;;;:::i;:::-;111257:6;;111264:1;111257:9;;;;;;;:::i;:::-;;;;;;:16;;;;;;;;;;:::i;:::-;111275:6;;111282:1;111275:9;;;;;;;:::i;:::-;;;;;;:17;;;;;;;;;;:::i;111219:74::-;111308:8;111131:17;:196::i;:::-;111338:57;111373:6;;111338:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;111389:4;111338:34;:57::i;:::-;111426:29;::::0;-1:-1:-1;;;111426:29:0;;111449:4:::1;111426:29;::::0;::::1;4910:51:1::0;111406:17:0::1;::::0;111426:4:::1;-1:-1:-1::0;;;;;111426:14:0::1;::::0;::::1;::::0;4883:18:1;;111426:29:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;111406:49;;111482:12;111470:9;:24;111466:63;;;111503:26;;-1:-1:-1::0;;;111503:26:0::1;;;;;;;;;;;111466:63;111540:24;::::0;-1:-1:-1;;;111540:24:0;;::::1;::::0;::::1;19508:25:1::0;;;111540:4:0::1;-1:-1:-1::0;;;;;111540:13:0::1;::::0;::::1;::::0;19481:18:1;;111540:24:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;111575:31;111592:2;111596:9;111575:16;:31::i;:::-;111038:576;110805:809:::0;;;;;;;:::o;109980:788::-;110184:8;92328:25;92344:8;92328:15;:25::i;:::-;110235:4:::1;-1:-1:-1::0;;;;;110209:31:0::1;:6;;110216:1;110209:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;110209:14:0::1;:::i;:::-;-1:-1:-1::0;;;;;110209:31:0::1;;110205:57;;110249:13;;-1:-1:-1::0;;;110249:13:0::1;;;;;;;;;;;110205:57;110273:16;110292:9;110273:28;;110312:4;-1:-1:-1::0;;;;;110312:12:0::1;;110332:8;110312:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;110361:4;-1:-1:-1::0;;;;;110361:13:0::1;;110375:74;110383:6;;110390:1;110383:9;;;;;;;:::i;110375:74::-;110361:99;::::0;-1:-1:-1;;;;;;110361:99:0::1;::::0;;;;;;-1:-1:-1;;;;;22573:32:1;;;110361:99:0::1;::::0;::::1;22555:51:1::0;22622:18;;;22615:34;;;22528:18;;110361:99:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;110354:107;;;;:::i;:::-;110472:15;110490:17;110506:1;110490:6:::0;:17:::1;:::i;:::-;110472:35;;110518:21;110549:6;;110556:7;110549:15;;;;;;;:::i;:::-;;;;;;:18;;;;;;;;;;:::i;:::-;110542:40;::::0;-1:-1:-1;;;110542:40:0;;-1:-1:-1;;;;;4928:32:1;;;110542:40:0::1;::::0;::::1;4910:51:1::0;110542:36:0;;;::::1;::::0;::::1;::::0;4883:18:1;;110542:40:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;110518:64;;110593:46;110628:6;;110593:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;110636:2;110593:34;:46::i;:::-;110713:12;110697:13;110661:6;;110668:7;110661:15;;;;;;;:::i;:::-;;;;;;:18;;;;;;;;;;:::i;:::-;110654:40;::::0;-1:-1:-1;;;110654:40:0;;-1:-1:-1;;;;;4928:32:1;;;110654:40:0::1;::::0;::::1;4910:51:1::0;110654:36:0;;;::::1;::::0;::::1;::::0;4883:18:1;;110654:40:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:56;;;;:::i;:::-;:71;110650:110;;;110734:26;;-1:-1:-1::0;;;110734:26:0::1;;;;;;;;;;;110650:110;110194:574;;;109980:788:::0;;;;;;:::o;107211:497::-;107411:16;107392:8;92328:25;92344:8;92328:15;:25::i;:::-;107440:198:::1;107472:6;;107479:1;107472:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;107472:14:0::1;:::i;:::-;107501:12;:10;:12::i;:::-;107528:74;107536:6;;107543:1;107536:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;107536:14:0::1;:::i;:::-;107552:6;;107559:1;107552:9;;;;;;;:::i;:::-;;;;;;:12;;;;;;;;;;:::i;:::-;107566:6;;107573:1;107566:9;;;;;;;:::i;:::-;;;;;;:16;;;;;;;;;;:::i;:::-;107584:6;;107591:1;107584:9;;;;;;;:::i;107528:74::-;107617:7;107625:1;107617:10;;;;;;;;:::i;:::-;;;;;;;107440:17;:198::i;:::-;107649:26;107655:7;107664:6;;107649:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;107672:2;107649:5;:26::i;:::-;107693:7;107686:14;;92364:1;107211:497:::0;;;;;;;;:::o;92984:308::-;93057:14;93073;93114:6;-1:-1:-1;;;;;93104:16:0;:6;-1:-1:-1;;;;;93104:16:0;;93100:44;;93129:15;;-1:-1:-1;;;93129:15:0;;;;;;;;;;;93100:44;93183:6;-1:-1:-1;;;;;93174:15:0;:6;-1:-1:-1;;;;;93174:15:0;;:53;;93212:6;93220;93174:53;;;93193:6;93201;93174:53;93155:72;;-1:-1:-1;93155:72:0;-1:-1:-1;;;;;;93242:20:0;;93238:46;;93271:13;;-1:-1:-1;;;93271:13:0;;;;;;;;;;;93238:46;92984:308;;;;;:::o;95059:730::-;95144:24;95201:1;95185:6;:13;:17;95181:43;;;95211:13;;-1:-1:-1;;;95211:13:0;;;;;;;;;;;95181:43;95259:13;;:17;;95275:1;95259:17;:::i;:::-;-1:-1:-1;;;;;95245:32:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;95245:32:0;;95235:42;;95301:8;95288:7;95296:1;95288:10;;;;;;;;:::i;:::-;;;;;;;;;;:21;95338:13;;95320:15;95362:420;95386:7;95382:1;:11;95362:420;;;95415:15;95462:1;-1:-1:-1;;;;;95433:31:0;:6;95440:1;95433:9;;;;;;;;:::i;:::-;;;;;;;:17;;;-1:-1:-1;;;;;95433:31:0;;:68;;95484:6;95491:1;95484:9;;;;;;;;:::i;:::-;;;;;;;:17;;;95433:68;;;95467:14;95433:68;95415:86;;95533:12;95548:64;95556:6;95563:1;95556:9;;;;;;;;:::i;:::-;;;;;;;:14;;;95572:6;95579:1;95572:9;;;;;;;;:::i;:::-;;;;;;;:12;;;95586:6;95593:1;95586:9;;;;;;;;:::i;:::-;;;;;;;:16;;;95604:7;95548;:64::i;:::-;95631:34;;-1:-1:-1;;;95631:34:0;;-1:-1:-1;;;;;4928:32:1;;;95631:34:0;;;4910:51:1;95533:79:0;;-1:-1:-1;95631:28:0;;;;;;4883:18:1;;95631:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95627:144;;;95709:4;-1:-1:-1;;;;;95703:24:0;;95728:7;95736:1;95728:10;;;;;;;;:::i;:::-;;;;;;;95740:6;95747:1;95740:9;;;;;;;;:::i;:::-;;;;;;;:14;;;95703:52;;;;;;;;;;;;;;;23346:25:1;;;-1:-1:-1;;;;;23407:32:1;23402:2;23387:18;;23380:60;23334:2;23319:18;;23172:274;95703:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95686:7;95694:5;:1;95698;95694:5;:::i;:::-;95686:14;;;;;;;;:::i;:::-;;;;;;:69;;;;;95627:144;95400:382;;95395:3;;;;;:::i;:::-;;;;95362:420;;;;95170:619;95059:730;;;;:::o;99766:840::-;100072:15;100089;100106:17;100053:8;92328:25;92344:8;92328:15;:25::i;:::-;100157:195:::1;100185:6;100206;100227;100248:14;100277;100306:10;100331;100157:13;:195::i;:::-;100136:216:::0;;-1:-1:-1;100136:216:0;-1:-1:-1;100363:12:0::1;100378:47;100386:6:::0;100394;100402;100410:14:::1;100378:7;:47::i;:::-;100363:62;;100436:54;100454:6;100462:12;:10;:12::i;:::-;100476:4;100482:7;100436:17;:54::i;:::-;100501;100519:6;100527:12;:10;:12::i;:::-;100541:4;100547:7;100501:17;:54::i;:::-;100578:20;::::0;-1:-1:-1;;;100578:20:0;;-1:-1:-1;;;;;4928:32:1;;;100578:20:0::1;::::0;::::1;4910:51:1::0;100578:16:0;::::1;::::0;::::1;::::0;4883:18:1;;100578:20:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100566:32;;100125:481;99766:840:::0;;;;;;;;;;;;;;:::o;120056:889::-;120313:21;120336;120359:18;120379;120437:65;120458:6;120466;120474;120482:8;120492:9;120437:20;:65::i;:::-;120410:92;;-1:-1:-1;120410:92:0;-1:-1:-1;120410:92:0;;-1:-1:-1;120410:92:0;;-1:-1:-1;120587:24:0;120626:18;;120622:153;;120671:34;120685:10;120697:7;;120671:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;120661:44;;120736:7;120761:1;120744:7;:14;:18;;;;:::i;:::-;120736:27;;;;;;;;:::i;:::-;;;;;;;120720:43;;120622:153;120789:18;;120785:153;;120834:34;120848:10;120860:7;;120834:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;120824:44;;120899:7;120924:1;120907:7;:14;:18;;;;:::i;:::-;120899:27;;;;;;;;:::i;:::-;;;;;;;120883:43;;120785:153;120399:546;120056:889;;;;;;;;;;;;;;:::o;93329:626::-;93430:12;93481:14;93430:12;-1:-1:-1;;;;;93524:22:0;;;:51;;93567:8;93524:51;;;93549:15;93524:51;93591:64;;-1:-1:-1;;;93591:64:0;;-1:-1:-1;;;;;4928:32:1;;;93591:64:0;;;4910:51:1;93506:69:0;;-1:-1:-1;93608:15:0;93591:55;;;;;;4883:18:1;;93591:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;93586:103;;93664:25;;-1:-1:-1;;;93664:25:0;;;;;;;;;;;93586:103;93703:14;93719;93737:26;93748:6;93756;93737:10;:26::i;:::-;93799:40;;-1:-1:-1;;23840:2:1;23836:15;;;23832:24;;93799:40:0;;;23820:37:1;23891:15;;;23887:24;23873:12;;;23866:46;23958:14;;23951:22;23946:3;23942:32;23928:12;;;23921:54;93702:61:0;;-1:-1:-1;93702:61:0;-1:-1:-1;93774:12:0;;23991::1;;93799:40:0;;;;;;;;;;;;93789:51;;;;;;93774:66;;93858:89;93906:7;-1:-1:-1;;;;;93893:36:0;;:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90784:4;90778:11;90819:4;90810:14;;90803:32;;;90872:34;90865:4;90856:14;;90849:58;-1:-1:-1;90928:14:0;;90921:38;;;;90985:42;90973:55;;91058:4;91049:14;;91042:28;;;91133:4;91126;91117:14;;91107:31;91100:4;91091:14;;91084:55;91192:4;91185;91176:14;;;91166:31;;90519:696;93858:89;93851:96;93329:626;-1:-1:-1;;;;;;;;;;93329:626:0:o;109193:750::-;109419:8;92328:25;92344:8;92328:15;:25::i;:::-;109440:196:::1;109472:6;;109479:1;109472:9;;;;;;;:::i;109440:196::-;109647:15;109665:17;109681:1;109665:6:::0;:17:::1;:::i;:::-;109647:35;;109693:21;109724:6;;109731:7;109724:15;;;;;;;:::i;:::-;;;;;;:18;;;;;;;;;;:::i;:::-;109717:40;::::0;-1:-1:-1;;;109717:40:0;;-1:-1:-1;;;;;4928:32:1;;;109717:40:0::1;::::0;::::1;4910:51:1::0;109717:36:0;;;::::1;::::0;::::1;::::0;4883:18:1;;109717:40:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;109693:64;;109768:46;109803:6;;109768:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;109811:2;109768:34;:46::i;:::-;109888:12;109872:13;109836:6;;109843:7;109836:15;;;;;;;:::i;:::-;;;;;;:18;;;;;;;;;;:::i;:::-;109829:40;::::0;-1:-1:-1;;;109829:40:0;;-1:-1:-1;;;;;4928:32:1;;;109829:40:0::1;::::0;::::1;4910:51:1::0;109829:36:0;;;::::1;::::0;::::1;::::0;4883:18:1;;109829:40:0::1;4764:203:1::0;94562:460:0;94710:16;94728;94758:14;94778:26;94789:6;94797;94778:10;:26::i;:::-;94757:47;;;94816:16;94834;94862:41;94870:6;94878;94886;94894:8;94862:7;:41::i;:::-;-1:-1:-1;;;;;94856:60:0;;:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94815:103;;;;;94962:6;-1:-1:-1;;;;;94952:16:0;:6;-1:-1:-1;;;;;94952:16:0;;:62;;94995:8;95005;94952:62;;;94972:8;94982;94952:62;94929:85;;;;-1:-1:-1;94562:460:0;-1:-1:-1;;;;;;;;94562:460:0:o;105710:642::-;105904:24;105885:8;92328:25;92344:8;92328:15;:25::i;:::-;105971:4:::1;-1:-1:-1::0;;;;;105945:31:0::1;:6;;105952:1;105945:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;105945:14:0::1;:::i;:::-;-1:-1:-1::0;;;;;105945:31:0::1;;105941:57;;105985:13;;-1:-1:-1::0;;;105985:13:0::1;;;;;;;;;;;105941:57;106019:32;106033:9;106044:6;;106019:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;106009:42;;106096:12;106066:7;106091:1;106074:7;:14;:18;;;;:::i;:::-;106066:27;;;;;;;;:::i;:::-;;;;;;;:42;106062:81;;;106117:26;;-1:-1:-1::0;;;106117:26:0::1;;;;;;;;;;;106062:81;106154:4;-1:-1:-1::0;;;;;106154:12:0::1;;106174:7;106182:1;106174:10;;;;;;;;:::i;:::-;;;;;;;106154:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;106205:4;-1:-1:-1::0;;;;;106205:13:0::1;;106219:74;106227:6;;106234:1;106227:9;;;;;;;:::i;106219:74::-;106295:7;106303:1;106295:10;;;;;;;;:::i;:::-;;;;;;;106205:101;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;22573:32:1;;;;22555:51;;22637:2;22622:18;;22615:34;22543:2;22528:18;;22381:274;106205:101:0::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;106198:109;;;;:::i;:::-;106318:26;106324:7;106333:6;;106318:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;117218:1034:::0;117420:14;117437:17;;;;:10;:17;:::i;:::-;117420:34;-1:-1:-1;117465:14:0;117482:17;;;;;;;;:::i;:::-;117465:34;-1:-1:-1;117510:17:0;-1:-1:-1;;;;;117531:17:0;;92232:42;117531:17;117530:46;;117568:8;117530:46;;;117560:4;117530:46;117510:66;;117587:39;117604:9;117615:10;117587:16;:39::i;:::-;117639:15;117679:9;-1:-1:-1;;;;;117669:19:0;:6;-1:-1:-1;;;;;117669:19:0;;117665:267;;117715:39;;-1:-1:-1;;;117715:39:0;;117748:4;117715:39;;;4910:51:1;-1:-1:-1;;;;;117715:24:0;;;;;4883:18:1;;117715:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117705:49;-1:-1:-1;;;;;;117773:43:0;;:7;;117781:18;117798:1;117773:7;117781:18;:::i;:::-;117773:27;;;;;;;:::i;:::-;;;;;;:30;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;117773:43:0;;117769:71;;117825:15;;-1:-1:-1;;;117825:15:0;;;;;;;;;;;117769:71;117855:65;117869:6;117877:7;117886:10;:24;;;117912:7;;117855:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:13;:65::i;:::-;117956:9;-1:-1:-1;;;;;117946:19:0;:6;-1:-1:-1;;;;;117946:19:0;;117942:267;;117992:39;;-1:-1:-1;;;117992:39:0;;118025:4;117992:39;;;4910:51:1;-1:-1:-1;;;;;117992:24:0;;;;;4883:18:1;;117992:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117982:49;-1:-1:-1;;;;;;118050:43:0;;:7;;118058:18;118075:1;118050:7;118058:18;:::i;:::-;118050:27;;;;;;;:::i;:::-;;;;;;:30;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;118050:43:0;;118046:71;;118102:15;;-1:-1:-1;;;118102:15:0;;;;;;;;;;;118046:71;118132:65;118146:6;118154:7;118163:10;:24;;;118189:7;;118132:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;118221:23;118235:8;118221:13;:23::i;:::-;117409:843;;;;117218:1034;;;;;;;:::o;100643:990::-;100913:19;100934:17;100953;100894:8;92328:25;92344:8;92328:15;:25::i;:::-;101010:206:::1;101038:5;101066:4;101086:6;101107:18;101140:9;101164:14;101193:12;101010:13;:206::i;:::-;100983:233:::0;;-1:-1:-1;100983:233:0;-1:-1:-1;101227:12:0::1;101242:53;101250:5:::0;101265:4:::1;101272:6:::0;101280:14:::1;101242:7;:53::i;:::-;101227:68;;101306:57;101324:5;101331:12;:10;:12::i;101306:57::-;101374:4;-1:-1:-1::0;;;;;101374:12:0::1;;101394:9;101374:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;101424:30:0::1;::::0;-1:-1:-1;;;101424:30:0;;-1:-1:-1;;;;;22573:32:1;;;101424:30:0::1;::::0;::::1;22555:51:1::0;22622:18;;;22615:34;;;101424:4:0::1;:13;::::0;-1:-1:-1;101424:13:0::1;::::0;-1:-1:-1;22528:18:1;;;-1:-1:-1;101424:30:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101417:38;;;;:::i;:::-;101478:20;::::0;-1:-1:-1;;;101478:20:0;;-1:-1:-1;;;;;4928:32:1;;;101478:20:0::1;::::0;::::1;4910:51:1::0;101478:16:0;::::1;::::0;::::1;::::0;4883:18:1;;101478:20:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101466:32;;101561:9;101549;:21;101545:80;;;101572:53;101589:12;:10;:12::i;:::-;101603:21;101615:9:::0;101603::::1;:21;:::i;:::-;101572:16;:53::i;:::-;100972:661;100643:990:::0;;;;;;;;;;;;:::o;106360:843::-;106573:24;106554:8;92328:25;92344:8;92328:15;:25::i;:::-;-1:-1:-1;;;;;106654:4:0::1;106614:45;:6:::0;;106621:17:::1;106637:1;106614:6:::0;106621:17:::1;:::i;:::-;106614:25;;;;;;;:::i;:::-;;;;;;:28;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;106614:45:0::1;;106610:71;;106668:13;;-1:-1:-1::0;;;106668:13:0::1;;;;;;;;;;;106610:71;106702:31;106716:8;106726:6;;106702:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;106692:41;;106778:12;106748:7;106773:1;106756:7;:14;:18;;;;:::i;:::-;106748:27;;;;;;;;:::i;:::-;;;;;;;:42;106744:81;;;106799:26;;-1:-1:-1::0;;;106799:26:0::1;;;;;;;;;;;106744:81;106836:198;106868:6;;106875:1;106868:9;;;;;;;:::i;:::-;:14;::::0;::::1;:9;::::0;;::::1;;:14:::0;;::::1;::::0;-1:-1:-1;106868:14:0::1;:::i;:::-;106897:12;:10;:12::i;:::-;106924:74;106932:6;;106939:1;106932:9;;;;;;;:::i;106924:74::-;107013:7;107021:1;107013:10;;;;;;;;:::i;106836:198::-;107045:37;107051:7;107060:6;;107045:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;107076:4;107045:5;:37::i;:::-;107093:4;-1:-1:-1::0;;;;;107093:13:0::1;;107107:7;107132:1;107115:7;:14;:18;;;;:::i;:::-;107107:27;;;;;;;;:::i;:::-;;;;;;;107093:42;;;;;;;;;;;;;19508:25:1::0;;19496:2;19481:18;;19362:177;107093:42:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;107146:49;107163:2;107167:7;107192:1;107175:7;:14;:18;;;;:::i;:::-;107167:27;;;;;;;;:::i;:::-;;;;;;;107146:16;:49::i;:::-;106360:843:::0;;;;;;;;;:::o;97366:757::-;97551:15;97568;97596:13;97625:8;-1:-1:-1;;;;;97612:30:0;;97643:6;97651;97659;97612:54;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;97596:70;-1:-1:-1;;;;;;97683:19:0;;97679:65;;97727:1;97730;97719:13;;;;;;;97679:65;97757:16;97775;97795:45;97807:6;97815;97823;97831:8;97795:11;:45::i;:::-;97756:84;;;;97851:20;97881:5;-1:-1:-1;;;;;97874:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;97851:50;-1:-1:-1;97851:50:0;97925:20;97937:8;97925:9;:20;:::i;:::-;97924:37;;;;:::i;:::-;97914:47;-1:-1:-1;98055:12:0;98031:20;98043:8;98031:9;:20;:::i;:::-;98030:37;;;;:::i;:::-;98020:47;;97585:538;;;;97366:757;;;;;;;;;:::o;105062:640::-;105278:24;105259:8;92328:25;92344:8;92328:15;:25::i;:::-;105325:31:::1;105339:8;105349:6;;105325:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;105315:41;;105401:12;105371:7;105396:1;105379:7;:14;:18;;;;:::i;:::-;105371:27;;;;;;;;:::i;:::-;;;;;;;:42;105367:81;;;105422:26;;-1:-1:-1::0;;;105422:26:0::1;;;;;;;;;;;105367:81;105459:198;105491:6;;105498:1;105491:9;;;;;;;:::i;105459:198::-;105668:26;105674:7;105683:6;;105668:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;95826:1503:::0;96046:15;96063;96080:17;96110:13;96139:8;-1:-1:-1;;;;;96126:30:0;;96157:6;96165;96173;96126:54;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;96110:70;-1:-1:-1;96192:16:0;;;-1:-1:-1;;;;;96286:19:0;;;96282:177;;96344:5;-1:-1:-1;;;;;96337:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;96322:42;;96402:45;96414:6;96422;96430;96438:8;96402:11;:45::i;:::-;96379:68;;-1:-1:-1;96379:68:0;-1:-1:-1;96282:177:0;96473:13;;:30;;;;-1:-1:-1;96490:13:0;;96473:30;96469:853;;;96542:14;;-1:-1:-1;96558:14:0;;-1:-1:-1;92157:7:0;96600:28;96610:17;96558:14;96542;96610:17;:::i;:::-;96600:9;:28::i;:::-;:48;;;;:::i;:::-;96588:60;;96469:853;;;96681:22;96706:50;96721:14;96737:8;96747;96706:14;:50::i;:::-;96681:75;;96793:14;96775;:32;96771:540;;96850:14;;-1:-1:-1;96866:14:0;-1:-1:-1;96866:14:0;96912:82;96948:8;96922:22;96932:12;96850:14;96922:22;:::i;:::-;96921:35;;;;:::i;:::-;96985:8;96959:22;96969:12;96959:7;:22;:::i;:::-;96958:35;;;;:::i;:::-;96912:8;:82::i;:::-;96900:94;;96771:540;;;97035:22;97060:50;97075:14;97091:8;97101;97060:14;:50::i;:::-;97035:75;-1:-1:-1;97167:14:0;;-1:-1:-1;97035:75:0;;-1:-1:-1;97213:82:0;97249:8;97223:22;97233:12;97035:75;97223:22;:::i;:::-;97222:35;;;;:::i;:::-;97286:8;97260:22;97270:12;97260:7;:22;:::i;97213:82::-;97201:94;;97016:295;96771:540;96666:656;96469:853;96099:1230;;;;95826:1503;;;;;;;;;;:::o;102547:691::-;102801:19;102822:17;102782:8;92328:25;92344:8;92328:15;:25::i;:::-;102879:226:::1;102909:5;102937:4;102957:6;102978:9;103002:14;103031:12;103066:4;103086:8;102879:15;:226::i;:::-;102852:253:::0;;-1:-1:-1;102852:253:0;-1:-1:-1;103116:37:0::1;103130:5:::0;103137:2;102852:253;103116:13:::1;:37::i;:::-;103164:24;::::0;-1:-1:-1;;;103164:24:0;;::::1;::::0;::::1;19508:25:1::0;;;103164:4:0::1;-1:-1:-1::0;;;;;103164:13:0::1;::::0;::::1;::::0;19481:18:1;;103164:24:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;103199:31;103216:2;103220:9;103199:16;:31::i;:::-;102547:691:::0;;;;;;;;;;;:::o;121678:920::-;121820:13;121846:10;121865:39;121873:6;121881;121889:4;121895:8;121865:7;:39::i;:::-;121846:59;;121918:17;121959:6;-1:-1:-1;;;;;121944:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121938:39;;:2;:39;:::i;:::-;121918:59;;121988:17;122029:6;-1:-1:-1;;;;;122014:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122008:39;;:2;:39;:::i;:::-;122115:37;;-1:-1:-1;;;122115:37:0;;;;;23346:25:1;;;-1:-1:-1;;;;;23407:32:1;;;23387:18;;;23380:60;121988:59:0;;-1:-1:-1;122081:9:0;;122060:18;;122115:17;;;;;;23319:18:1;;122115:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122101:51;;122164:15;122181;122202:66;122220:6;122228;122236:4;122242:8;122252:10;122264:3;122202:17;:66::i;:::-;-1:-1:-1;122163:105:0;;-1:-1:-1;122163:105:0;-1:-1:-1;122310:9:0;122292:14;122163:105;122302:4;122292:14;:::i;:::-;122291:28;;;;:::i;:::-;122281:38;-1:-1:-1;122359:9:0;122341:14;:7;122351:4;122341:14;:::i;:::-;122340:28;;;;:::i;:::-;122330:38;-1:-1:-1;122400:9:0;122386:10;:3;122392:4;122386:10;:::i;:::-;122385:24;;;;:::i;:::-;122379:30;-1:-1:-1;122455:9:0;122434:17;:10;122447:4;122434:17;:::i;:::-;122433:31;;;;:::i;:::-;122420:44;-1:-1:-1;122527:7:0;122516;122420:44;122488:10;:3;122494:4;122488:10;:::i;:::-;122487:25;;;;:::i;:::-;122486:37;;;;:::i;:::-;122485:49;;;;:::i;:::-;122477:57;-1:-1:-1;122577:12:0;122477:57;122585:4;122577:12;:::i;:::-;122555:17;:10;122568:4;122555:17;:::i;:::-;122554:36;;;;:::i;:::-;122547:43;121678:920;-1:-1:-1;;;;;;;;;;;121678:920:0:o;111651:1527::-;111926:17;;111975:21;111987:9;111975;:21;:::i;:::-;111956:40;-1:-1:-1;112026:7:0;112060:9;-1:-1:-1;;;;;;;112084:16:0;;;112080:357;;112133:5;112121:8;:17;112117:60;;112147:30;;-1:-1:-1;;;112147:30:0;;;;;;;;;;;112117:60;112211:4;112192:24;;112231:4;-1:-1:-1;;;;;112231:12:0;;112251:5;112231:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;112080:357;;;112296:10;;112292:52;;112315:29;;-1:-1:-1;;;112315:29:0;;;;;;;;;;;112292:52;112359:66;112377:8;112387:12;:10;:12::i;:::-;112409:4;112416:8;112359:17;:66::i;:::-;112449:69;112458:8;112468:9;112479;112490;112501:7;;112510;;112449:8;:69::i;:::-;112529:26;112545:9;112529:15;:26::i;:::-;112566:12;112581:80;112589:16;;;;:9;:16;:::i;:::-;112607:9;:16;;;;;;;;;;:::i;:::-;112625:9;:16;;;;;;;;;;:::i;:::-;112643:9;:17;;;;;;;;;;:::i;112581:80::-;112566:95;;112678:5;112674:378;;;112712:31;;-1:-1:-1;;;112712:31:0;;112737:4;112712:31;;;4910:51:1;-1:-1:-1;;;;;112712:16:0;;;;;4883:18:1;;112712:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;112774:26;;-1:-1:-1;;;112774:26:0;;-1:-1:-1;;;;;4928:32:1;;;112774:26:0;;;4910:51:1;112700:43:0;;-1:-1:-1;112758:13:0;;112781:5;112774:20;;;;4883:18:1;;112774:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;112758:42;-1:-1:-1;112815:51:0;-1:-1:-1;;;;;112815:24:0;;112758:42;112856:9;112815:24;:51::i;:::-;112881:36;;-1:-1:-1;;;112881:36:0;;;;;23346:25:1;;;-1:-1:-1;;;;;23407:32:1;;;23387:18;;;23380:60;112881:21:0;;;;;23319:18:1;;112881:36:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;112932:43:0;;-1:-1:-1;;;;;;;;112932:24:0;;112965:5;112973:1;112932:24;:43::i;:::-;112685:302;112674:378;;;113020:20;;-1:-1:-1;;;113020:20:0;;-1:-1:-1;;;;;4928:32:1;;;113020:20:0;;;4910:51:1;113020:16:0;;;;;4883:18:1;;113020:20:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;113008:32;;112674:378;113064:22;113078:7;113064:13;:22::i;:::-;113097:31;113111:16;;;;:9;:16;:::i;:::-;113097:13;:31::i;:::-;113139;113153:16;;;;;;;;:::i;113139:31::-;111945:1233;;;;111651:1527;;;;;;;;;;;;:::o;103317:715::-;103600:17;103581:8;92328:25;92344:8;92328:15;:25::i;:::-;103646:226:::1;103676:5;103704:4;103724:6;103745:9;103769:14;103798:12;103833:4;103853:8;103646:15;:226::i;:::-;103908:38;::::0;-1:-1:-1;;;103908:38:0;;103940:4:::1;103908:38;::::0;::::1;4910:51:1::0;103630:242:0;;-1:-1:-1;103883:64:0::1;::::0;-1:-1:-1;103897:5:0;;103904:2;;-1:-1:-1;;;;;103908:23:0;::::1;::::0;::::1;::::0;4883:18:1;;103908:38:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;103883:13;:64::i;:::-;103958:24;::::0;-1:-1:-1;;;103958:24:0;;::::1;::::0;::::1;19508:25:1::0;;;103958:4:0::1;-1:-1:-1::0;;;;;103958:13:0::1;::::0;::::1;::::0;19481:18:1;;103958:24:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;103993:31;104010:2;104014:9;103993:16;:31::i;:::-;103317:715:::0;;;;;;;;;;:::o;92381:124::-;92464:15;92453:8;:26;92449:48;;;92488:9;;-1:-1:-1;;;92488:9:0;;;;;;;;;;;92449:48;92381:124;:::o;86784:458::-;86846:14;86751:17;-1:-1:-1;;;;;86738:30:0;86896:10;86738:30;86873:362;;-1:-1:-1;;;87130:14:0;87126:23;87113:37;87109:2;87105:46;86784:458;:::o;86873:362::-;-1:-1:-1;86122:10:0;;86784:458::o;81941:205::-;82069:68;;-1:-1:-1;;;;;27417:15:1;;;82069:68:0;;;27399:34:1;27469:15;;27449:18;;;27442:43;27501:18;;;27494:34;;;82042:96:0;;82062:5;;-1:-1:-1;;;82092:27:0;27334:18:1;;82069:68:0;;;;-1:-1:-1;;82069:68:0;;;;;;;;;;;;;;-1:-1:-1;;;;;82069:68:0;-1:-1:-1;;;;;;82069:68:0;;;;;;;;;;82042:19;:96::i;:::-;81941:205;;;;:::o;123126:370::-;123257:1;123237:5;-1:-1:-1;;;;;123237:17:0;;:21;123229:30;;;;;;123331:69;;;-1:-1:-1;;;;;27417:15:1;;;123331:69:0;;;27399:34:1;27469:15;;;27449:18;;;27442:43;27501:18;;;;27494:34;;;123331:69:0;;;;;;;;;;27334:18:1;;;;123331:69:0;;;;;;;-1:-1:-1;;;;;123331:69:0;-1:-1:-1;;;123331:69:0;;;123306:105;;-1:-1:-1;;;;123306:10:0;;;;:105;;123331:69;123306:105;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;123270:141;;;;123430:7;:57;;;;-1:-1:-1;123442:11:0;;:16;;:44;;;123473:4;123462:24;;;;;;;;;;;;:::i;:::-;123422:66;;;;;;123218:278;;123126:370;;;;:::o;107861:1295::-;107987:13;;107969:15;108011:1138;108031:7;108027:1;:11;108011:1138;;;108061:14;108081:40;108092:6;108099:1;108092:9;;;;;;;;:::i;:::-;;;;;;;:14;;;108108:6;108115:1;108108:9;;;;;;;;:::i;:::-;;;;;;;:12;;;108081:10;:40::i;:::-;108060:61;;;108136:12;108151:74;108159:6;108166:1;108159:9;;;;;;;;:::i;:::-;;;;;;;:14;;;108175:6;108182:1;108175:9;;;;;;;;:::i;:::-;;;;;;;:12;;;108189:6;108196:1;108189:9;;;;;;;;:::i;:::-;;;;;;;:16;;;108207:6;108214:1;108207:9;;;;;;;;:::i;:::-;;;;;;;:17;;;108151:7;:74::i;:::-;108136:89;;108240:19;108274:20;108364:16;108386:78;108398:6;108405:1;108398:9;;;;;;;;:::i;:::-;;;;;;;:14;;;108414:6;108421:1;108414:9;;;;;;;;:::i;:::-;;;;;;;:12;;;108428:6;108435:1;108428:9;;;;;;;;:::i;:::-;;;;;;;:16;;;108446:6;108453:1;108446:9;;;;;;;;:::i;:::-;;;;;;;:17;;;108386:11;:78::i;:::-;108363:101;;;108602:8;108568:6;108575:1;108568:9;;;;;;;;:::i;:::-;;;;;;;;;;;:14;108561:38;;-1:-1:-1;;;108561:38:0;;-1:-1:-1;;;;;4928:32:1;;;108561:38:0;;;4910:51:1;108561:32:0;;;;;;4883:18:1;;108561:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:49;;;;:::i;:::-;108547:63;;108309:317;108661:4;-1:-1:-1;;;;;108655:24:0;;108680:11;108693:6;108700:1;108693:9;;;;;;;;:::i;:::-;;;;;;;:14;;;108655:53;;;;;;;;;;;;;;;23346:25:1;;;-1:-1:-1;;;;;23407:32:1;23402:2;23387:18;;23380:60;23334:2;23319:18;;23172:274;108655:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;108640:68;;108724:18;108744;108784:6;-1:-1:-1;;;;;108766:24:0;:6;108773:1;108766:9;;;;;;;;:::i;:::-;;;;;;;:14;;;-1:-1:-1;;;;;108766:24:0;;:116;;108857:12;108879:1;108766:116;;;108819:1;108823:12;108766:116;108723:159;;;;108897:10;108930:1;108914:6;:13;:17;;;;:::i;:::-;108910:1;:21;:154;;109061:3;108910:154;;;108951:90;108959:6;108966:5;:1;108970;108966:5;:::i;:::-;108959:13;;;;;;;;:::i;:::-;;;;;;;:18;;;108979:6;108986:1;108990;108986:5;;;;:::i;:::-;108979:13;;;;;;;;:::i;:::-;;;;;;;:16;;;108997:6;109004:1;109008;109004:5;;;;:::i;:::-;108997:13;;;;;;;;:::i;:::-;;;;;;;:20;;;109019:6;109026:1;109030;109026:5;;;;:::i;:::-;109019:13;;;;;;;;:::i;108951:90::-;109124:12;;;109134:1;109124:12;;;;;;;;;-1:-1:-1;;;109079:58:0;;;108897:167;;-1:-1:-1;;;;;;109079:16:0;;;;;:58;;109096:10;;109108;;108897:167;;109079:58;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108045:1104;;;;;;;108040:3;;;;;:::i;:::-;;;;108011:1138;;122606:186;122720:12;;;122680;122720;;;;;;;;;-1:-1:-1;;;;;122698:7:0;;;122713:5;;122698:35;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122679:54;;;122749:7;122744:40;;122765:19;;-1:-1:-1;;;122765:19:0;;;;;;;;;;;122744:40;122668:124;122606:186;;:::o;104149:905::-;104272:13;;104254:15;104296:751;104320:7;104316:1;:11;104296:751;;;104350:14;104370:40;104381:6;104388:1;104381:9;;;;;;;;:::i;104370:40::-;-1:-1:-1;104349:61:0;-1:-1:-1;104425:17:0;104445:7;104453:5;:1;104457;104453:5;:::i;:::-;104445:14;;;;;;;;:::i;:::-;;;;;;;104425:34;;104475:18;104495;104535:6;-1:-1:-1;;;;;104517:24:0;:6;104524:1;104517:9;;;;;;;;:::i;:::-;;;;;;;:14;;;-1:-1:-1;;;;;104517:24:0;;:110;;104605:9;104624:1;104517:110;;;104570:1;104574:9;104517:110;104474:153;;;;104642:10;104675:1;104659:6;:13;:17;;;;:::i;:::-;104655:1;:21;:154;;104806:3;104655:154;;;104696:90;104704:6;104711:5;:1;104715;104711:5;:::i;:::-;104704:13;;;;;;;;:::i;:::-;;;;;;;:18;;;104724:6;104731:1;104735;104731:5;;;;:::i;:::-;104724:13;;;;;;;;:::i;:::-;;;;;;;:16;;;104742:6;104749:1;104753;104749:5;;;;:::i;:::-;104742:13;;;;;;;;:::i;:::-;;;;;;;:20;;;104764:6;104771:1;104775;104771:5;;;;:::i;104696:90::-;104642:167;;104830:74;104838:6;104845:1;104838:9;;;;;;;;:::i;:::-;;;;;;;:14;;;104854:6;104861:1;104854:9;;;;;;;;:::i;:::-;;;;;;;:12;;;104868:6;104875:1;104868:9;;;;;;;;:::i;:::-;;;;;;;:16;;;104886:6;104893:1;104886:9;;;;;;;;:::i;104830:74::-;-1:-1:-1;;;;;104824:86:0;;104929:10;104958;104987:2;105018:1;105008:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;105008:12:0;;104824:211;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104334:713;;;;;104329:3;;;;;:::i;:::-;;;;104296:751;;;;104243:811;104149:905;;;:::o;98131:1598::-;98375:15;98392;98441:10;98424:14;:27;98420:68;;;98460:28;;-1:-1:-1;;;98460:28:0;;;;;;;;;;;98420:68;98520:10;98503:14;:27;98499:68;;;98539:28;;-1:-1:-1;;;98539:28:0;;;;;;;;;;;98499:68;98646:60;;-1:-1:-1;;;98646:60:0;;98630:13;;-1:-1:-1;;;;;98659:14:0;98646:36;;;;:60;;98683:6;;98691;;98699;;98646:60;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98630:76;-1:-1:-1;;;;;;98721:19:0;;98717:123;;98765:63;;-1:-1:-1;;;98765:63:0;;-1:-1:-1;;;;;98778:14:0;98765:39;;;;:63;;98805:6;;98813;;98821;;98765:63;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98757:71;;98717:123;98851:16;98869;98889:51;98901:6;98909;98917;98925:14;98889:11;:51::i;:::-;98850:90;;;;98955:8;98967:1;98955:13;:30;;;;-1:-1:-1;98972:13:0;;98955:30;98951:771;;;99024:14;;-1:-1:-1;99040:14:0;;-1:-1:-1;98951:771:0;;;99088:22;99113:50;99128:14;99144:8;99154;99113:14;:50::i;:::-;99088:75;;99200:14;99182;:32;99178:533;;99256:10;99239:14;:27;99235:61;;;99275:21;;-1:-1:-1;;;99275:21:0;;;;;;;;;;;99235:61;99337:14;;-1:-1:-1;99353:14:0;-1:-1:-1;99353:14:0;99178:533;;;99409:22;99434:50;99449:14;99465:8;99475;99434:14;:50::i;:::-;99409:75;;99528:14;99510;:32;;99503:40;;;;:::i;:::-;99583:10;99566:14;:27;99562:61;;;99602:21;;-1:-1:-1;;;99602:21:0;;;;;;;;;;;99562:61;99664:14;-1:-1:-1;99680:14:0;;-1:-1:-1;99178:533:0;99073:649;98951:771;98409:1320;;;98131:1598;;;;;;;;;;:::o;118323:729::-;118413:14;118430:17;;;;:10;:17;:::i;:::-;118413:34;-1:-1:-1;118458:14:0;118475:17;;;;;;;;:::i;:::-;118458:34;-1:-1:-1;118503:12:0;118518:62;118526:6;118458:34;118542:17;;;;;;;;:::i;:::-;118561:18;;;;;;;;:::i;118518:62::-;118503:77;-1:-1:-1;118591:58:0;-1:-1:-1;;;;;118591:29:0;;118621:10;118503:77;118639:9;118591:29;:58::i;:::-;118661:14;118681:26;118692:6;118700;118681:10;:26::i;:::-;-1:-1:-1;118755:31:0;;-1:-1:-1;;;118755:31:0;;118780:4;118755:31;;;4910:51:1;118660:47:0;;-1:-1:-1;118719:15:0;;;;-1:-1:-1;;;;;118755:16:0;;;;;4883:18:1;;118755:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118718:68;;;;118798:15;118815;118844:6;-1:-1:-1;;;;;118834:16:0;:6;-1:-1:-1;;;;;118834:16:0;;:58;;118875:7;118884;118834:58;;;118854:7;118863;118834:58;118797:95;;;;118917:10;:21;;;118907:7;:31;118903:65;;;118947:21;;-1:-1:-1;;;118947:21:0;;;;;;;;;;;118903:65;118993:10;:21;;;118983:7;:31;118979:65;;;119023:21;;-1:-1:-1;;;119023:21:0;;;;;;;;;;;118979:65;118402:650;;;;;;;;118323:729;;:::o;116703:478::-;116826:24;116853:31;116867:8;116877:6;116853:13;:31::i;:::-;116826:58;;116929:12;116899:7;116924:1;116907:7;:14;:18;;;;:::i;:::-;116899:27;;;;;;;;:::i;:::-;;;;;;;:42;116895:81;;;116950:26;;-1:-1:-1;;;116950:26:0;;;;;;;;;;;116895:81;116987:12;117002:74;117010:6;117017:1;117010:9;;;;;;;;:::i;:::-;;;;;;;:14;;;117026:6;117033:1;117026:9;;;;;;;;:::i;:::-;;;;;;;:12;;;117040:6;117047:1;117040:9;;;;;;;;:::i;:::-;;;;;;;:16;;;117058:6;117065:1;117058:9;;;;;;;;:::i;117002:74::-;116987:89;;117087:38;117101:7;117110:4;117116:8;117087:13;:38::i;:::-;117136:37;117142:7;117151:6;117167:4;117136:5;:37::i;121079:562::-;121137:14;121154:12;:10;:12::i;:::-;121137:29;-1:-1:-1;121177:15:0;-1:-1:-1;;;;;;;121207:14:0;;;121203:431;;121248:37;;-1:-1:-1;;;121248:37:0;;121279:4;121248:37;;;4910:51:1;121255:4:0;-1:-1:-1;;;;;121248:22:0;;;;4883:18:1;;121248:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121238:47;-1:-1:-1;121304:11:0;;121300:133;;121336:29;;-1:-1:-1;;;121336:29:0;;;;;19508:25:1;;;121342:4:0;-1:-1:-1;;;;;121336:20:0;;;;19481:18:1;;121336:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121384:33;121401:6;121409:7;121384:16;:33::i;121203:431::-;121475:38;;-1:-1:-1;;;121475:38:0;;121507:4;121475:38;;;4910:51:1;-1:-1:-1;;;;;121475:23:0;;;;;4883:18:1;;121475:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121465:48;-1:-1:-1;121532:11:0;;121528:95;;121564:43;-1:-1:-1;;;;;121564:26:0;;121591:6;121599:7;121564:26;:43::i;6390:1673::-;6438:7;6462:1;6467;6462:6;6458:47;;-1:-1:-1;6492:1:0;;6390:1673;-1:-1:-1;6390:1673:0:o;6458:47::-;7196:14;7230:1;7219:7;7224:1;7219:4;:7::i;:::-;:12;;7213:1;:19;;7196:36;;7698:1;7687:6;7683:1;:10;;;;;:::i;:::-;;7674:6;:19;7673:26;;7664:35;;7748:1;7737:6;7733:1;:10;;;;;:::i;:::-;;7724:6;:19;7723:26;;7714:35;;7798:1;7787:6;7783:1;:10;;;;;:::i;:::-;;7774:6;:19;7773:26;;7764:35;;7848:1;7837:6;7833:1;:10;;;;;:::i;:::-;;7824:6;:19;7823:26;;7814:35;;7898:1;7887:6;7883:1;:10;;;;;:::i;:::-;;7874:6;:19;7873:26;;7864:35;;7948:1;7937:6;7933:1;:10;;;;;:::i;:::-;;7924:6;:19;7923:26;;7914:35;;7998:1;7987:6;7983:1;:10;;;;;:::i;:::-;;7974:6;:19;7973:26;;7964:35;;8021:23;8025:6;8037;8033:1;:10;;;;;:::i;:::-;;8021:3;:23::i;:::-;8014:30;6390:1673;-1:-1:-1;;;6390:1673:0:o;94181:344::-;94315:15;94347:7;94358:1;94347:12;94343:45;;94368:20;;-1:-1:-1;;;94368:20:0;;;;;;;;;;;94343:45;94403:13;;;:30;;-1:-1:-1;94420:13:0;;94403:30;94399:66;;;94442:23;;-1:-1:-1;;;94442:23:0;;;;;;;;;;;94399:66;94509:8;94487:18;94497:8;94487:7;:18;:::i;:::-;94486:31;;;;:::i;:::-;94476:41;94181:344;-1:-1:-1;;;;94181:344:0:o;618:106::-;676:7;707:1;703;:5;:13;;715:1;703:13;;;711:1;703:13;696:20;;618:106;;;;;:::o;122800:318::-;122913:1;122893:5;-1:-1:-1;;;;;122893:17:0;;:21;122885:30;;;;;;122973:59;;;-1:-1:-1;;;;;22573:32:1;;;122973:59:0;;;22555:51:1;22622:18;;;;22615:34;;;122973:59:0;;;;;;;;;;22528:18:1;;;;122973:59:0;;;;;;;-1:-1:-1;;;;;122973:59:0;-1:-1:-1;;;122973:59:0;;;122962:71;;-1:-1:-1;;;;122962:10:0;;;;:71;;122973:59;122962:71;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122926:107;;;;123052:7;:57;;;;-1:-1:-1;123064:11:0;;:16;;:44;;;123095:4;123084:24;;;;;;;;;;;;:::i;:::-;123044:66;;;;;113274:1103;113504:14;113521:16;;;;:9;:16;:::i;:::-;113504:33;-1:-1:-1;113548:14:0;113565:16;;;;;;;;:::i;:::-;113548:33;-1:-1:-1;113592:11:0;113606:16;;;;;;;;:::i;:::-;113592:30;-1:-1:-1;113633:15:0;113651:17;;;;;;;;:::i;:::-;113633:35;;113679:12;113694:40;113702:6;113710;113718;113726:7;113694;:40::i;:::-;113679:55;;113763:16;113781;113809:4;-1:-1:-1;;;;;113803:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;113762:66;;;;;92157:7;113847:8;:29;;:62;;;;92157:7;113880:8;:29;;113847:62;113843:93;;;113918:18;;-1:-1:-1;;;113918:18:0;;;;;;;;;;;113843:93;113747:201;;113975:6;-1:-1:-1;;;;;113964:17:0;:7;-1:-1:-1;;;;;113964:17:0;;113960:200;;-1:-1:-1;;;;;114002:40:0;;:7;;114010:18;114027:1;114002:7;114010:18;:::i;:::-;114002:27;;;;;;;:::i;:::-;;;;;;:30;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;114002:40:0;;113998:68;;114051:15;;-1:-1:-1;;;114051:15:0;;;;;;;;;;;113998:68;114081:67;114095:7;114104:9;114115;:23;;;114140:7;;114081:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;114185:6;-1:-1:-1;;;;;114174:17:0;:7;-1:-1:-1;;;;;114174:17:0;;114170:200;;-1:-1:-1;;;;;114212:40:0;;:7;;114220:18;114237:1;114212:7;114220:18;:::i;:::-;114212:27;;;;;;;:::i;:::-;;;;;;:30;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;114212:40:0;;114208:68;;114261:15;;-1:-1:-1;;;114261:15:0;;;;;;;;;;;114208:68;114291:67;114305:7;114314:9;114325;:23;;;114350:7;;114291:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;113493:884;;;;;113274:1103;;;;;;;;:::o;114445:741::-;114514:14;114531:16;;;;:9;:16;:::i;:::-;114514:33;-1:-1:-1;114558:14:0;114575:16;;;;;;;;:::i;:::-;114558:33;-1:-1:-1;114602:11:0;114616:16;;;;;;;;:::i;:::-;114602:30;-1:-1:-1;114643:15:0;114661:17;;;;;;;;:::i;:::-;114643:35;;114689:12;114704:40;114712:6;114720;114728;114736:7;114704;:40::i;:::-;114910:39;;-1:-1:-1;;;114910:39:0;;114943:4;114910:39;;;4910:51:1;114689:55:0;;-1:-1:-1;114756:15:0;;;;114792:292;;114825:6;;114846;;114867;;114888:7;;-1:-1:-1;;;;;114910:24:0;;;;;4883:18:1;;114910:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;114964;;-1:-1:-1;;;114964:39:0;;114997:4;114964:39;;;4910:51:1;-1:-1:-1;;;;;114964:24:0;;;;;4883:18:1;;114964:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;115018:9;:20;;;115053:9;:20;;;114792:18;:292::i;:::-;114755:329;;;;115095:36;115109:6;115117:4;115123:7;115095:13;:36::i;:::-;115142;115156:6;115164:4;115170:7;115142:13;:36::i;82415:582::-;82745:10;;;82744:62;;-1:-1:-1;82761:39:0;;-1:-1:-1;;;82761:39:0;;82785:4;82761:39;;;9205:34:1;-1:-1:-1;;;;;9275:15:1;;;9255:18;;;9248:43;82761:15:0;;;;;9140:18:1;;82761:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;82744:62;82722:166;;;;-1:-1:-1;;;82722:166:0;;29026:2:1;82722:166:0;;;29008:21:1;29065:2;29045:18;;;29038:30;29104:34;29084:18;;;29077:62;-1:-1:-1;;;29155:18:1;;;29148:52;29217:19;;82722:166:0;;;;;;;;;82926:62;;-1:-1:-1;;;;;22573:32:1;;82926:62:0;;;22555:51:1;22622:18;;;22615:34;;;82899:90:0;;82919:5;;-1:-1:-1;;;82949:22:0;22528:18:1;;82926:62:0;22381:274:1;84644:716:0;85068:23;85094:69;85122:4;85094:69;;;;;;;;;;;;;;;;;85102:5;-1:-1:-1;;;;;85094:27:0;;;:69;;;;;:::i;:::-;85178:17;;85068:95;;-1:-1:-1;85178:21:0;85174:179;;85275:10;85264:30;;;;;;;;;;;;:::i;:::-;85256:85;;;;-1:-1:-1;;;85256:85:0;;29449:2:1;85256:85:0;;;29431:21:1;29488:2;29468:18;;;29461:30;29527:34;29507:18;;;29500:62;-1:-1:-1;;;29578:18:1;;;29571:40;29628:19;;85256:85:0;29247:406:1;81756:177:0;81866:58;;-1:-1:-1;;;;;22573:32:1;;81866:58:0;;;22555:51:1;22622:18;;;22615:34;;;81839:86:0;;81859:5;;-1:-1:-1;;;81889:23:0;22528:18:1;;81866:58:0;22381:274:1;8540:1019:0;8592:7;;8679:3;8670:12;;;:16;8666:102;;8717:3;8707:13;;;;8739;8666:102;8795:2;8786:11;;;:15;8782:99;;8832:2;8822:12;;;;8853;8782:99;8908:2;8899:11;;;:15;8895:99;;8945:2;8935:12;;;;8966;8895:99;9021:2;9012:11;;;:15;9008:99;;9058:2;9048:12;;;;9079;9008:99;9134:1;9125:10;;;:14;9121:96;;9170:1;9160:11;;;;9190;9121:96;9244:1;9235:10;;;:14;9231:96;;9280:1;9270:11;;;;9300;9231:96;9354:1;9345:10;;;:14;9341:96;;9390:1;9380:11;;;;9410;9341:96;9464:1;9455:10;;;:14;9451:66;;9500:1;9490:11;9545:6;8540:1019;-1:-1:-1;;8540:1019:0:o;115289:1357::-;115570:15;115587;115636:10;115619:14;:27;115615:68;;;115655:28;;-1:-1:-1;;;115655:28:0;;;;;;;;;;;115615:68;115715:10;115698:14;:27;115694:68;;;115734:28;;-1:-1:-1;;;115734:28:0;;;;;;;;;;;115694:68;115774:16;115792;115812:45;115824:6;115832;115840;115848:8;115812:11;:45::i;:::-;115773:84;;;;115872:8;115884:1;115872:13;:30;;;;-1:-1:-1;115889:13:0;;115872:30;115868:771;;;115941:14;;-1:-1:-1;115957:14:0;;-1:-1:-1;115868:771:0;;;116005:22;116030:50;116045:14;116061:8;116071;116030:14;:50::i;:::-;116005:75;;116117:14;116099;:32;116095:533;;116173:10;116156:14;:27;116152:61;;;116192:21;;-1:-1:-1;;;116192:21:0;;;;;;;;;;;116152:61;116254:14;;-1:-1:-1;116270:14:0;-1:-1:-1;116270:14:0;116095:533;;;116326:22;116351:50;116366:14;116382:8;116392;116351:14;:50::i;:::-;116326:75;;116445:14;116427;:32;;116420:40;;;;:::i;:::-;116500:10;116483:14;:27;116479:61;;;116519:21;;-1:-1:-1;;;116519:21:0;;;;;;;;;;;116479:61;116581:14;-1:-1:-1;116597:14:0;;-1:-1:-1;116095:533:0;115990:649;115868:771;115604:1042;;115289:1357;;;;;;;;;;;:::o;75826:229::-;75963:12;75995:52;76017:6;76025:4;76031:1;76034:12;75963;77200;77214:23;77241:6;-1:-1:-1;;;;;77241:11:0;77260:5;77267:4;77241:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77199:73;;;;77290:69;77317:6;77325:7;77334:10;77346:12;77290:26;:69::i;:::-;77283:76;76912:455;-1:-1:-1;;;;;;;76912:455:0:o;79485:644::-;79670:12;79699:7;79695:427;;;79727:10;:17;79748:1;79727:22;79723:290;;-1:-1:-1;;;;;73365:19:0;;;79937:60;;;;-1:-1:-1;;;79937:60:0;;30267:2:1;79937:60:0;;;30249:21:1;30306:2;30286:18;;;30279:30;30345:31;30325:18;;;30318:59;30394:18;;79937:60:0;30065:353:1;79937:60:0;-1:-1:-1;80034:10:0;80027:17;;79695:427;80077:33;80085:10;80097:12;80832:17;;:21;80828:388;;81064:10;81058:17;81121:15;81108:10;81104:2;81100:19;81093:44;80828:388;81191:12;81184:20;;-1:-1:-1;;;81184:20:0;;;;;;;;:::i;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:134;218:20;;247:31;218:20;247:31;:::i;:::-;150:134;;;:::o;289:118::-;375:5;368:13;361:21;354:5;351:32;341:60;;397:1;394;387:12;412:381;489:8;499:6;553:3;546:4;538:6;534:17;530:27;520:55;;571:1;568;561:12;520:55;-1:-1:-1;594:20:1;;-1:-1:-1;;;;;626:30:1;;623:50;;;669:1;666;659:12;623:50;706:4;698:6;694:17;682:29;;766:3;759:4;749:6;746:1;742:14;734:6;730:27;726:38;723:47;720:67;;;783:1;780;773:12;798:1544;1021:6;1029;1037;1045;1053;1061;1069;1077;1085;1093;1146:3;1134:9;1125:7;1121:23;1117:33;1114:53;;;1163:1;1160;1153:12;1114:53;1202:9;1189:23;1221:31;1246:5;1221:31;:::i;:::-;1271:5;-1:-1:-1;1328:2:1;1313:18;;1300:32;1341:33;1300:32;1341:33;:::i;:::-;1393:7;-1:-1:-1;1452:2:1;1437:18;;1424:32;1465:30;1424:32;1465:30;:::i;:::-;1514:7;-1:-1:-1;1573:2:1;1558:18;;1545:32;1586:33;1545:32;1586:33;:::i;:::-;1638:7;-1:-1:-1;1692:3:1;1677:19;;1664:33;;-1:-1:-1;1744:3:1;1729:19;;1716:33;;-1:-1:-1;1800:3:1;1785:19;;1772:33;-1:-1:-1;;;;;1854:14:1;;;1851:34;;;1881:1;1878;1871:12;1851:34;1920:84;1996:7;1987:6;1976:9;1972:22;1920:84;:::i;:::-;2023:8;;-1:-1:-1;1894:110:1;-1:-1:-1;2111:3:1;2096:19;;2083:33;;-1:-1:-1;2128:16:1;;;2125:36;;;2157:1;2154;2147:12;2125:36;;2196:86;2274:7;2263:8;2252:9;2248:24;2196:86;:::i;:::-;2170:112;;2301:8;2291:18;;;2328:8;2318:18;;;798:1544;;;;;;;;;;;;;:::o;2743:941::-;2862:6;2870;2878;2886;2894;2902;2910;2918;2971:3;2959:9;2950:7;2946:23;2942:33;2939:53;;;2988:1;2985;2978:12;2939:53;3027:9;3014:23;3046:31;3071:5;3046:31;:::i;:::-;3096:5;-1:-1:-1;3153:2:1;3138:18;;3125:32;3166:33;3125:32;3166:33;:::i;:::-;3218:7;-1:-1:-1;3277:2:1;3262:18;;3249:32;3290:30;3249:32;3290:30;:::i;:::-;3339:7;-1:-1:-1;3393:2:1;3378:18;;3365:32;;-1:-1:-1;3444:3:1;3429:19;;3416:33;;-1:-1:-1;3496:3:1;3481:19;;3468:33;;-1:-1:-1;3553:3:1;3538:19;;3525:33;3567;3525;3567;:::i;:::-;3619:7;3609:17;;;3673:3;3662:9;3658:19;3645:33;3635:43;;2743:941;;;;;;;;;;;:::o;3942:817::-;4089:6;4097;4105;4113;4121;4129;4182:3;4170:9;4161:7;4157:23;4153:33;4150:53;;;4199:1;4196;4189:12;4150:53;4235:9;4222:23;4212:33;;4292:2;4281:9;4277:18;4264:32;4254:42;;4347:2;4336:9;4332:18;4319:32;-1:-1:-1;;;;;4366:6:1;4363:30;4360:50;;;4406:1;4403;4396:12;4360:50;4445:84;4521:7;4512:6;4501:9;4497:22;4445:84;:::i;:::-;4548:8;;-1:-1:-1;4419:110:1;-1:-1:-1;;4633:2:1;4618:18;;4605:32;4646:31;4605:32;4646:31;:::i;:::-;4696:5;4686:15;;;4748:3;4737:9;4733:19;4720:33;4710:43;;3942:817;;;;;;;;:::o;4972:748::-;5110:6;5118;5126;5134;5142;5195:3;5183:9;5174:7;5170:23;5166:33;5163:53;;;5212:1;5209;5202:12;5163:53;5248:9;5235:23;5225:33;;5309:2;5298:9;5294:18;5281:32;-1:-1:-1;;;;;5328:6:1;5325:30;5322:50;;;5368:1;5365;5358:12;5322:50;5407:84;5483:7;5474:6;5463:9;5459:22;5407:84;:::i;:::-;5510:8;;-1:-1:-1;5381:110:1;-1:-1:-1;;5595:2:1;5580:18;;5567:32;5608:31;5567:32;5608:31;:::i;:::-;4972:748;;;;-1:-1:-1;4972:748:1;;5710:2;5695:18;5682:32;;4972:748;-1:-1:-1;;4972:748:1:o;5947:127::-;6008:10;6003:3;5999:20;5996:1;5989:31;6039:4;6036:1;6029:15;6063:4;6060:1;6053:15;6079:275;6150:2;6144:9;6215:2;6196:13;;-1:-1:-1;;6192:27:1;6180:40;;-1:-1:-1;;;;;6235:34:1;;6271:22;;;6232:62;6229:88;;;6297:18;;:::i;:::-;6333:2;6326:22;6079:275;;-1:-1:-1;6079:275:1:o;6359:183::-;6419:4;-1:-1:-1;;;;;6444:6:1;6441:30;6438:56;;;6474:18;;:::i;:::-;-1:-1:-1;6519:1:1;6515:14;6531:4;6511:25;;6359:183::o;6547:1411::-;6710:6;6718;6726;6734;6742;6795:3;6783:9;6774:7;6770:23;6766:33;6763:53;;;6812:1;6809;6802:12;6763:53;6852:9;6839:23;-1:-1:-1;;;;;6922:2:1;6914:6;6911:14;6908:34;;;6938:1;6935;6928:12;6908:34;6976:6;6965:9;6961:22;6951:32;;7021:7;7014:4;7010:2;7006:13;7002:27;6992:55;;7043:1;7040;7033:12;6992:55;7079:2;7066:16;7101:4;7125:60;7141:43;7181:2;7141:43;:::i;:::-;7125:60;:::i;:::-;7219:15;;;7301:1;7297:10;;;;7289:19;;7285:28;;;7250:12;;;;7325:19;;;7322:39;;;7357:1;7354;7347:12;7322:39;7381:11;;;;7401:142;7417:6;7412:3;7409:15;7401:142;;;7483:17;;7471:30;;7434:12;;;;7521;;;;7401:142;;;7562:5;-1:-1:-1;;7605:18:1;;7592:32;;-1:-1:-1;;7636:16:1;;;7633:36;;;7665:1;7662;7655:12;7633:36;;7704:86;7782:7;7771:8;7760:9;7756:24;7704:86;:::i;:::-;7809:8;;-1:-1:-1;7678:112:1;-1:-1:-1;7863:38:1;;-1:-1:-1;7897:2:1;7882:18;;7863:38;:::i;7963:632::-;8134:2;8186:21;;;8256:13;;8159:18;;;8278:22;;;8105:4;;8134:2;8357:15;;;;8331:2;8316:18;;;8105:4;8400:169;8414:6;8411:1;8408:13;8400:169;;;8475:13;;8463:26;;8544:15;;;;8509:12;;;;8436:1;8429:9;8400:169;;;-1:-1:-1;8586:3:1;;7963:632;-1:-1:-1;;;;;;7963:632:1:o;8600:388::-;8668:6;8676;8729:2;8717:9;8708:7;8704:23;8700:32;8697:52;;;8745:1;8742;8735:12;8697:52;8784:9;8771:23;8803:31;8828:5;8803:31;:::i;:::-;8853:5;-1:-1:-1;8910:2:1;8895:18;;8882:32;8923:33;8882:32;8923:33;:::i;:::-;8975:7;8965:17;;;8600:388;;;;;:::o;9302:891::-;9354:5;9402:4;9390:9;9385:3;9381:19;9377:30;9374:50;;;9420:1;9417;9410:12;9374:50;9453:2;9447:9;9495:4;9487:6;9483:17;9566:6;9554:10;9551:22;-1:-1:-1;;;;;9518:10:1;9515:34;9512:62;9509:88;;;9577:18;;:::i;:::-;9613:2;9606:22;9646:6;-1:-1:-1;9646:6:1;9676:23;;9708:33;9676:23;9708:33;:::i;:::-;9750:23;;9825:2;9810:18;;9797:32;9838:33;9797:32;9838:33;:::i;:::-;9899:2;9887:15;;9880:32;9964:2;9949:18;;9936:32;9977:30;9936:32;9977:30;:::i;:::-;10035:2;10023:15;;10016:32;10100:2;10085:18;;10072:32;10113:33;10072:32;10113:33;:::i;:::-;10174:2;10162:15;;;;10155:32;9302:891;;-1:-1:-1;;9302:891:1:o;10198:1004::-;10314:6;10322;10375:2;10363:9;10354:7;10350:23;10346:32;10343:52;;;10391:1;10388;10381:12;10343:52;10427:9;10414:23;10404:33;;10456:2;10509;10498:9;10494:18;10481:32;-1:-1:-1;;;;;10528:6:1;10525:30;10522:50;;;10568:1;10565;10558:12;10522:50;10591:22;;10644:4;10636:13;;10632:27;-1:-1:-1;10622:55:1;;10673:1;10670;10663:12;10622:55;10709:2;10696:16;10732:60;10748:43;10788:2;10748:43;:::i;10732:60::-;10826:15;;;10908:1;10904:10;;;;10896:19;;10892:28;;;10857:12;;;;10932:19;;;10929:39;;;10964:1;10961;10954:12;10929:39;10988:11;;;;11008:164;11024:6;11019:3;11016:15;11008:164;;;11092:37;11121:7;11116:3;11092:37;:::i;:::-;11087:3;11080:50;11159:2;11154:3;11150:12;11143:19;;11050:4;11045:3;11041:14;11034:21;;11008:164;;;11191:5;11181:15;;;;;;;10198:1004;;;;;:::o;11207:247::-;11266:6;11319:2;11307:9;11298:7;11294:23;11290:32;11287:52;;;11335:1;11332;11325:12;11287:52;11374:9;11361:23;11393:31;11418:5;11393:31;:::i;11651:1010::-;11779:6;11787;11795;11803;11811;11819;11827;11835;11843;11896:3;11884:9;11875:7;11871:23;11867:33;11864:53;;;11913:1;11910;11903:12;11864:53;11952:9;11939:23;11971:31;11996:5;11971:31;:::i;:::-;12021:5;-1:-1:-1;12078:2:1;12063:18;;12050:32;12091:33;12050:32;12091:33;:::i;:::-;12143:7;-1:-1:-1;12202:2:1;12187:18;;12174:32;12215:30;12174:32;12215:30;:::i;:::-;12264:7;-1:-1:-1;12318:2:1;12303:18;;12290:32;;-1:-1:-1;12369:3:1;12354:19;;12341:33;;-1:-1:-1;12421:3:1;12406:19;;12393:33;;-1:-1:-1;12473:3:1;12458:19;;12445:33;;-1:-1:-1;12530:3:1;12515:19;;12502:33;12544;12502;12544;:::i;:::-;12596:7;12586:17;;;12650:3;12639:9;12635:19;12622:33;12612:43;;11651:1010;;;;;;;;;;;:::o;12990:1475::-;13204:6;13212;13220;13228;13236;13244;13252;13260;13268;13321:3;13309:9;13300:7;13296:23;13292:33;13289:53;;;13338:1;13335;13328:12;13289:53;13377:9;13364:23;13396:31;13421:5;13396:31;:::i;:::-;13446:5;-1:-1:-1;13503:2:1;13488:18;;13475:32;13516:33;13475:32;13516:33;:::i;:::-;13568:7;-1:-1:-1;13627:2:1;13612:18;;13599:32;13640:30;13599:32;13640:30;:::i;:::-;13689:7;-1:-1:-1;13748:2:1;13733:18;;13720:32;13761:33;13720:32;13761:33;:::i;:::-;13813:7;-1:-1:-1;13867:3:1;13852:19;;13839:33;;-1:-1:-1;13923:3:1;13908:19;;13895:33;-1:-1:-1;;;;;13977:14:1;;;13974:34;;;14004:1;14001;13994:12;13974:34;14043:84;14119:7;14110:6;14099:9;14095:22;14043:84;:::i;:::-;14146:8;;-1:-1:-1;14017:110:1;-1:-1:-1;14234:3:1;14219:19;;14206:33;;-1:-1:-1;14251:16:1;;;14248:36;;;14280:1;14277;14270:12;14248:36;;14319:86;14397:7;14386:8;14375:9;14371:24;14319:86;:::i;:::-;14293:112;;14424:8;14414:18;;;14451:8;14441:18;;;12990:1475;;;;;;;;;;;:::o;14470:665::-;14553:6;14561;14569;14577;14630:3;14618:9;14609:7;14605:23;14601:33;14598:53;;;14647:1;14644;14637:12;14598:53;14686:9;14673:23;14705:31;14730:5;14705:31;:::i;:::-;14755:5;-1:-1:-1;14812:2:1;14797:18;;14784:32;14825:33;14784:32;14825:33;:::i;:::-;14877:7;-1:-1:-1;14936:2:1;14921:18;;14908:32;14949:30;14908:32;14949:30;:::i;:::-;14998:7;-1:-1:-1;15057:2:1;15042:18;;15029:32;15070:33;15029:32;15070:33;:::i;:::-;14470:665;;;;-1:-1:-1;14470:665:1;;-1:-1:-1;;14470:665:1:o;15140:152::-;15196:5;15241:3;15232:6;15227:3;15223:16;15219:26;15216:46;;;15258:1;15255;15248:12;15216:46;-1:-1:-1;15280:6:1;15140:152;-1:-1:-1;15140:152:1:o;15297:1175::-;15519:6;15527;15535;15543;15551;15559;15567;15620:3;15608:9;15599:7;15595:23;15591:33;15588:53;;;15637:1;15634;15627:12;15588:53;15676:9;15663:23;15695:31;15720:5;15695:31;:::i;:::-;15745:5;-1:-1:-1;15797:2:1;15782:18;;15769:32;;-1:-1:-1;15820:59:1;15871:7;15866:2;15851:18;;15820:59;:::i;:::-;15810:69;;15930:3;15919:9;15915:19;15902:33;-1:-1:-1;;;;;15995:2:1;15987:6;15984:14;15981:34;;;16011:1;16008;16001:12;15981:34;16050:84;16126:7;16117:6;16106:9;16102:22;16050:84;:::i;:::-;16153:8;;-1:-1:-1;16024:110:1;-1:-1:-1;16241:3:1;16226:19;;16213:33;;-1:-1:-1;16258:16:1;;;16255:36;;;16287:1;16284;16277:12;16255:36;;16326:86;16404:7;16393:8;16382:9;16378:24;16326:86;:::i;:::-;15297:1175;;;;-1:-1:-1;15297:1175:1;;-1:-1:-1;15297:1175:1;;;;16300:112;;-1:-1:-1;;;15297:1175:1:o;16477:799::-;16587:6;16595;16603;16611;16619;16627;16635;16688:3;16676:9;16667:7;16663:23;16659:33;16656:53;;;16705:1;16702;16695:12;16656:53;16744:9;16731:23;16763:31;16788:5;16763:31;:::i;:::-;16813:5;-1:-1:-1;16870:2:1;16855:18;;16842:32;16883:30;16842:32;16883:30;:::i;:::-;16932:7;-1:-1:-1;16986:2:1;16971:18;;16958:32;;-1:-1:-1;17037:2:1;17022:18;;17009:32;;-1:-1:-1;17088:3:1;17073:19;;17060:33;;-1:-1:-1;17145:3:1;17130:19;;17117:33;17159;17117;17159;:::i;:::-;17211:7;17201:17;;;17265:3;17254:9;17250:19;17237:33;17227:43;;16477:799;;;;;;;;;;:::o;17281:734::-;17373:6;17381;17389;17397;17405;17458:3;17446:9;17437:7;17433:23;17429:33;17426:53;;;17475:1;17472;17465:12;17426:53;17514:9;17501:23;17533:31;17558:5;17533:31;:::i;:::-;17583:5;-1:-1:-1;17640:2:1;17625:18;;17612:32;17653:33;17612:32;17653:33;:::i;:::-;17705:7;-1:-1:-1;17764:2:1;17749:18;;17736:32;17777:30;17736:32;17777:30;:::i;:::-;17826:7;-1:-1:-1;17885:2:1;17870:18;;17857:32;17898:33;17857:32;17898:33;:::i;:::-;17281:734;;;;-1:-1:-1;17281:734:1;;18004:3;17989:19;17976:33;;17281:734;-1:-1:-1;;17281:734:1:o;18020:803::-;18121:6;18129;18137;18145;18153;18161;18214:3;18202:9;18193:7;18189:23;18185:33;18182:53;;;18231:1;18228;18221:12;18182:53;18270:9;18257:23;18289:31;18314:5;18289:31;:::i;:::-;18339:5;-1:-1:-1;18396:2:1;18381:18;;18368:32;18409:33;18368:32;18409:33;:::i;:::-;18461:7;-1:-1:-1;18520:2:1;18505:18;;18492:32;18533:30;18492:32;18533:30;:::i;:::-;18582:7;-1:-1:-1;18641:2:1;18626:18;;18613:32;18654:33;18613:32;18654:33;:::i;:::-;18020:803;;;;-1:-1:-1;18020:803:1;;18760:3;18745:19;;18732:33;;18812:3;18797:19;;;18784:33;;-1:-1:-1;18020:803:1;-1:-1:-1;;18020:803:1:o;18828:529::-;18905:6;18913;18921;18974:2;18962:9;18953:7;18949:23;18945:32;18942:52;;;18990:1;18987;18980:12;18942:52;19029:9;19016:23;19048:31;19073:5;19048:31;:::i;:::-;19098:5;-1:-1:-1;19155:2:1;19140:18;;19127:32;19168:33;19127:32;19168:33;:::i;:::-;19220:7;-1:-1:-1;19279:2:1;19264:18;;19251:32;19292:33;19251:32;19292:33;:::i;:::-;19344:7;19334:17;;;18828:529;;;;;:::o;19544:1521::-;19790:6;19798;19806;19814;19822;19830;19838;19846;19854;19862;19915:3;19903:9;19894:7;19890:23;19886:33;19883:53;;;19932:1;19929;19922:12;19883:53;19971:9;19958:23;19990:31;20015:5;19990:31;:::i;:::-;20040:5;-1:-1:-1;20092:2:1;20077:18;;20064:32;;-1:-1:-1;20143:2:1;20128:18;;20115:32;;-1:-1:-1;20166:59:1;20217:7;20212:2;20197:18;;20166:59;:::i;:::-;20156:69;;20276:3;20265:9;20261:19;20248:33;-1:-1:-1;;;;;20341:2:1;20333:6;20330:14;20327:34;;;20357:1;20354;20347:12;20327:34;20396:84;20472:7;20463:6;20452:9;20448:22;20396:84;:::i;:::-;20499:8;;-1:-1:-1;20370:110:1;-1:-1:-1;20587:3:1;20572:19;;20559:33;;-1:-1:-1;20604:16:1;;;20601:36;;;20633:1;20630;20623:12;20601:36;;20672:86;20750:7;20739:8;20728:9;20724:24;20672:86;:::i;:::-;20777:8;;-1:-1:-1;20646:112:1;-1:-1:-1;;20864:3:1;20849:19;;20836:33;20878;20836;20878;:::i;:::-;20930:7;-1:-1:-1;20989:3:1;20974:19;;20961:33;21003:30;20961:33;21003:30;:::i;:::-;21052:7;21042:17;;;19544:1521;;;;;;;;;;;;;:::o;21070:224::-;21152:6;21205:3;21193:9;21184:7;21180:23;21176:33;21173:53;;;21222:1;21219;21212:12;21173:53;21245:43;21280:7;21269:9;21245:43;:::i;21299:127::-;21360:10;21355:3;21351:20;21348:1;21341:31;21391:4;21388:1;21381:15;21415:4;21412:1;21405:15;21431:128;21498:9;;;21519:11;;;21516:37;;;21533:18;;:::i;21564:127::-;21625:10;21620:3;21616:20;21613:1;21606:31;21656:4;21653:1;21646:15;21680:4;21677:1;21670:15;21696:245;21775:6;21783;21836:2;21824:9;21815:7;21811:23;21807:32;21804:52;;;21852:1;21849;21842:12;21804:52;-1:-1:-1;;21875:16:1;;21931:2;21916:18;;;21910:25;21875:16;;21910:25;;-1:-1:-1;21696:245:1:o;21946:241::-;22002:6;22055:2;22043:9;22034:7;22030:23;22026:32;22023:52;;;22071:1;22068;22061:12;22023:52;22110:9;22097:23;22129:28;22151:5;22129:28;:::i;22192:184::-;22262:6;22315:2;22303:9;22294:7;22290:23;22286:32;22283:52;;;22331:1;22328;22321:12;22283:52;-1:-1:-1;22354:16:1;;22192:184;-1:-1:-1;22192:184:1:o;22660:245::-;22727:6;22780:2;22768:9;22759:7;22755:23;22751:32;22748:52;;;22796:1;22793;22786:12;22748:52;22828:9;22822:16;22847:28;22869:5;22847:28;:::i;22910:127::-;22971:10;22966:3;22962:20;22959:1;22952:31;23002:4;22999:1;22992:15;23026:4;23023:1;23016:15;23042:125;23107:9;;;23128:10;;;23125:36;;;23141:18;;:::i;23451:135::-;23490:3;23511:17;;;23508:43;;23531:18;;:::i;:::-;-1:-1:-1;23578:1:1;23567:13;;23451:135::o;24014:251::-;24084:6;24137:2;24125:9;24116:7;24112:23;24108:32;24105:52;;;24153:1;24150;24143:12;24105:52;24185:9;24179:16;24204:31;24229:5;24204:31;:::i;24270:306::-;24358:6;24366;24374;24427:2;24415:9;24406:7;24402:23;24398:32;24395:52;;;24443:1;24440;24433:12;24395:52;24472:9;24466:16;24456:26;;24522:2;24511:9;24507:18;24501:25;24491:35;;24566:2;24555:9;24551:18;24545:25;24535:35;;24270:306;;;;;:::o;24581:385::-;-1:-1:-1;;;;;24833:15:1;;;24815:34;;24885:15;;;;24880:2;24865:18;;24858:43;24944:14;;24937:22;24932:2;24917:18;;24910:50;24765:2;24750:18;;24581:385::o;24971:168::-;25044:9;;;25075;;25092:15;;;25086:22;;25072:37;25062:71;;25113:18;;:::i;25144:127::-;25205:10;25200:3;25196:20;25193:1;25186:31;25236:4;25233:1;25226:15;25260:4;25257:1;25250:15;25276:217;25316:1;25342;25332:132;;25386:10;25381:3;25377:20;25374:1;25367:31;25421:4;25418:1;25411:15;25449:4;25446:1;25439:15;25332:132;-1:-1:-1;25478:9:1;;25276:217::o;25498:273::-;25566:6;25619:2;25607:9;25598:7;25594:23;25590:32;25587:52;;;25635:1;25632;25625:12;25587:52;25667:9;25661:16;25717:4;25710:5;25706:16;25699:5;25696:27;25686:55;;25737:1;25734;25727:12;25776:422;25865:1;25908:5;25865:1;25922:270;25943:7;25933:8;25930:21;25922:270;;;26002:4;25998:1;25994:6;25990:17;25984:4;25981:27;25978:53;;;26011:18;;:::i;:::-;26061:7;26051:8;26047:22;26044:55;;;26081:16;;;;26044:55;26160:22;;;;26120:15;;;;25922:270;;;25926:3;25776:422;;;;;:::o;26203:806::-;26252:5;26282:8;26272:80;;-1:-1:-1;26323:1:1;26337:5;;26272:80;26371:4;26361:76;;-1:-1:-1;26408:1:1;26422:5;;26361:76;26453:4;26471:1;26466:59;;;;26539:1;26534:130;;;;26446:218;;26466:59;26496:1;26487:10;;26510:5;;;26534:130;26571:3;26561:8;26558:17;26555:43;;;26578:18;;:::i;:::-;-1:-1:-1;;26634:1:1;26620:16;;26649:5;;26446:218;;26748:2;26738:8;26735:16;26729:3;26723:4;26720:13;26716:36;26710:2;26700:8;26697:16;26692:2;26686:4;26683:12;26679:35;26676:77;26673:159;;;-1:-1:-1;26785:19:1;;;26817:5;;26673:159;26864:34;26889:8;26883:4;26864:34;:::i;:::-;26934:6;26930:1;26926:6;26922:19;26913:7;26910:32;26907:58;;;26945:18;;:::i;:::-;26983:20;;26203:806;-1:-1:-1;;;26203:806:1:o;27014:140::-;27072:5;27101:47;27142:4;27132:8;27128:19;27122:4;27101:47;:::i;27539:250::-;27624:1;27634:113;27648:6;27645:1;27642:13;27634:113;;;27724:11;;;27718:18;27705:11;;;27698:39;27670:2;27663:10;27634:113;;;-1:-1:-1;;27781:1:1;27763:16;;27756:27;27539:250::o;27794:287::-;27923:3;27961:6;27955:13;27977:66;28036:6;28031:3;28024:4;28016:6;28012:17;27977:66;:::i;:::-;28059:16;;;;;27794:287;-1:-1:-1;;27794:287:1:o;28086:270::-;28127:3;28165:5;28159:12;28192:6;28187:3;28180:19;28208:76;28277:6;28270:4;28265:3;28261:14;28254:4;28247:5;28243:16;28208:76;:::i;:::-;28338:2;28317:15;-1:-1:-1;;28313:29:1;28304:39;;;;28345:4;28300:50;;28086:270;-1:-1:-1;;28086:270:1:o;28361:458::-;28592:6;28581:9;28574:25;28635:6;28630:2;28619:9;28615:18;28608:34;28707:1;28703;28698:3;28694:11;28690:19;28682:6;28678:32;28673:2;28662:9;28658:18;28651:60;28747:3;28742:2;28731:9;28727:18;28720:31;28555:4;28768:45;28808:3;28797:9;28793:19;28785:6;28768:45;:::i;:::-;28760:53;28361:458;-1:-1:-1;;;;;;28361:458:1:o;30423:219::-;30572:2;30561:9;30554:21;30535:4;30592:44;30632:2;30621:9;30617:18;30609:6;30592:44;:::i

Swarm Source

ipfs://b68b2dd239bbcf1a487caca8c68abd0aa1b05af6b08469ed0ff93d5dde3bd1e6
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.