ETH Price: $2,914.35 (-10.08%)
Gas: 18 Gwei

Contract

0x7f72986e190BBd1D02daC52b8DdA82eEa363d313
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Unwind171717512023-05-02 7:56:59429 days ago1683014219IN
0x7f72986e...Ea363d313
0 ETH0.0166620450.00177292
Unwind170705852023-04-18 2:19:59444 days ago1681784399IN
0x7f72986e...Ea363d313
0 ETH0.0150353543.64069506
Unwind170705742023-04-18 2:17:35444 days ago1681784255IN
0x7f72986e...Ea363d313
0 ETH0.0156582243.92356244
Build170107692023-04-09 12:33:35452 days ago1681043615IN
0x7f72986e...Ea363d313
0 ETH0.0065707718.91408123
Build169788992023-04-04 23:56:59457 days ago1680652619IN
0x7f72986e...Ea363d313
0 ETH0.0089734126.56277855
Unwind168315552023-03-15 6:34:35477 days ago1678862075IN
0x7f72986e...Ea363d313
0 ETH0.0062760518.29028021
Liquidate167972122023-03-10 10:43:11482 days ago1678444991IN
0x7f72986e...Ea363d313
0 ETH0.0117221838.70559808
Liquidate167961932023-03-10 7:14:11482 days ago1678432451IN
0x7f72986e...Ea363d313
0 ETH0.0071175622.56849709
Liquidate167961902023-03-10 7:13:35482 days ago1678432415IN
0x7f72986e...Ea363d313
0 ETH0.0070251722.90455705
Liquidate167961872023-03-10 7:12:59482 days ago1678432379IN
0x7f72986e...Ea363d313
0 ETH0.0073226323.86086618
Liquidate167679612023-03-06 7:54:47486 days ago1678089287IN
0x7f72986e...Ea363d313
0 ETH0.0063529622.0689458
Liquidate167679602023-03-06 7:54:35486 days ago1678089275IN
0x7f72986e...Ea363d313
0 ETH0.0064912322.53220657
Build167391032023-03-02 6:28:11490 days ago1677738491IN
0x7f72986e...Ea363d313
0 ETH0.0074277522
Liquidate167295152023-02-28 22:07:11492 days ago1677622031IN
0x7f72986e...Ea363d313
0 ETH0.0081519427.81018877
Unwind166609912023-02-19 6:54:59501 days ago1676789699IN
0x7f72986e...Ea363d313
0 ETH0.0066674219.60995812
Unwind166541122023-02-18 7:42:59502 days ago1676706179IN
0x7f72986e...Ea363d313
0 ETH0.0088938526.26190221
Unwind166521902023-02-18 1:12:59503 days ago1676682779IN
0x7f72986e...Ea363d313
0 ETH0.009141426.71723669
Build166517692023-02-17 23:47:47503 days ago1676677667IN
0x7f72986e...Ea363d313
0 ETH0.009900927.41790351
Unwind166510332023-02-17 21:17:47503 days ago1676668667IN
0x7f72986e...Ea363d313
0 ETH0.0163248147.1839872
Unwind166444922023-02-16 23:11:47504 days ago1676589107IN
0x7f72986e...Ea363d313
0 ETH0.0141911640.31225065
Unwind166444912023-02-16 23:11:35504 days ago1676589095IN
0x7f72986e...Ea363d313
0 ETH0.0141946240.82621888
Liquidate166425762023-02-16 16:47:11504 days ago1676566031IN
0x7f72986e...Ea363d313
0 ETH0.0268885285.85562694
Unwind166420842023-02-16 15:07:59504 days ago1676560079IN
0x7f72986e...Ea363d313
0 ETH0.01881453.81625979
Unwind166399662023-02-16 8:01:35504 days ago1676534495IN
0x7f72986e...Ea363d313
0 ETH0.0104009130.15012768
Unwind166399652023-02-16 8:01:23504 days ago1676534483IN
0x7f72986e...Ea363d313
0 ETH0.0102587431.40351644
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To Value
156416022022-09-29 21:12:35644 days ago1664485955  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
OverlayV1Market

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSL 1.1 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-09-29
*/

// SPDX-License-Identifier: BUSL-1.1
// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/uniswap/v3-core/FullMath.sol


pragma solidity ^0.8.0;

/// COPIED FROM:
/// https://github.com/Uniswap/v3-core/blob/0.8/contracts/libraries/FullMath.sol

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of
/// @notice an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division
/// @dev where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision.
    /// @notice Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = 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(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

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

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

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (0 - denominator) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            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
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // 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 precoditions 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 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision.
    /// @notice Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            result = mulDiv(a, b, denominator);
            if (mulmod(a, b, denominator) > 0) {
                require(result < type(uint256).max);
                result++;
            }
        }
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/FixedCast.sol


pragma solidity 0.8.10;

library FixedCast {
    uint256 internal constant ONE_256 = 1e18; // 18 decimal places
    uint256 internal constant ONE_16 = 1e4; // 4 decimal places

    /// @dev casts a uint16 to a FixedPoint uint256 with 18 decimals
    function toUint256Fixed(uint16 value) internal pure returns (uint256) {
        uint256 multiplier = ONE_256 / ONE_16;
        return (uint256(value) * multiplier);
    }

    /// @dev casts a FixedPoint uint256 to a uint16 with 4 decimals
    function toUint16Fixed(uint256 value) internal pure returns (uint16) {
        uint256 divisor = ONE_256 / ONE_16;
        uint256 ret256 = value / divisor;
        require(ret256 <= type(uint16).max, "OVLV1: FixedCast out of bounds");
        return uint16(ret256);
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/utils/Errors.sol


// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity 0.8.10;

// solhint-disable

/**
 * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
 * supported.
 */
function _require(bool condition, uint256 errorCode) pure {
    if (!condition) _revert(errorCode);
}

/**
 * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
 */
function _revert(uint256 errorCode) pure {
    // We're going to dynamically create a revert string based on the error code, with the following format:
    // 'BAL#{errorCode}'
    // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
    //
    // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
    // number (8 to 16 bits) than the individual string characters.
    //
    // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
    // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
    // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
    assembly {
        // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
        // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
        // the '0' character.

        let units := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let tenths := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let hundreds := add(mod(errorCode, 10), 0x30)

        // With the individual characters, we can now construct the full string. The "BAL#" part is a known constant
        // (0x42414c23): we simply shift this by 24 (to provide space for the 3 bytes of the error code), and add the
        // characters to it, each shifted by a multiple of 8.
        // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
        // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
        // array).

        let revertReason := shl(
            200,
            add(0x42414c23000000, add(add(units, shl(8, tenths)), shl(16, hundreds)))
        )

        // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
        // message will have the following layout:
        // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]

        // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
        // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
        mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
        // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
        mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
        // The string length is fixed: 7 characters.
        mstore(0x24, 7)
        // Finally, the string itself is stored.
        mstore(0x44, revertReason)

        // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
        // the encoded message is therefore 4 + 32 + 32 + 32 = 100.
        revert(0, 100)
    }
}

library Errors {
    // Math
    uint256 internal constant ADD_OVERFLOW = 0;
    uint256 internal constant SUB_OVERFLOW = 1;
    uint256 internal constant SUB_UNDERFLOW = 2;
    uint256 internal constant MUL_OVERFLOW = 3;
    uint256 internal constant ZERO_DIVISION = 4;
    uint256 internal constant DIV_INTERNAL = 5;
    uint256 internal constant X_OUT_OF_BOUNDS = 6;
    uint256 internal constant Y_OUT_OF_BOUNDS = 7;
    uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
    uint256 internal constant INVALID_EXPONENT = 9;

    // Input
    uint256 internal constant OUT_OF_BOUNDS = 100;
    uint256 internal constant UNSORTED_ARRAY = 101;
    uint256 internal constant UNSORTED_TOKENS = 102;
    uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
    uint256 internal constant ZERO_TOKEN = 104;

    // Shared pools
    uint256 internal constant MIN_TOKENS = 200;
    uint256 internal constant MAX_TOKENS = 201;
    uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
    uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
    uint256 internal constant MINIMUM_BPT = 204;
    uint256 internal constant CALLER_NOT_VAULT = 205;
    uint256 internal constant UNINITIALIZED = 206;
    uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
    uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
    uint256 internal constant EXPIRED_PERMIT = 209;
    uint256 internal constant NOT_TWO_TOKENS = 210;
    uint256 internal constant DISABLED = 211;

    // Pools
    uint256 internal constant MIN_AMP = 300;
    uint256 internal constant MAX_AMP = 301;
    uint256 internal constant MIN_WEIGHT = 302;
    uint256 internal constant MAX_STABLE_TOKENS = 303;
    uint256 internal constant MAX_IN_RATIO = 304;
    uint256 internal constant MAX_OUT_RATIO = 305;
    uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
    uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
    uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
    uint256 internal constant INVALID_TOKEN = 309;
    uint256 internal constant UNHANDLED_JOIN_KIND = 310;
    uint256 internal constant ZERO_INVARIANT = 311;
    uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
    uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
    uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
    uint256 internal constant ORACLE_INVALID_INDEX = 315;
    uint256 internal constant ORACLE_BAD_SECS = 316;
    uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;
    uint256 internal constant AMP_ONGOING_UPDATE = 318;
    uint256 internal constant AMP_RATE_TOO_HIGH = 319;
    uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;
    uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;
    uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;
    uint256 internal constant RELAYER_NOT_CONTRACT = 323;
    uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;
    uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;
    uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;
    uint256 internal constant SWAPS_DISABLED = 327;
    uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;
    uint256 internal constant PRICE_RATE_OVERFLOW = 329;
    uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;
    uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;
    uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;
    uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;
    uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;
    uint256 internal constant OUT_OF_TARGET_RANGE = 335;
    uint256 internal constant UNHANDLED_EXIT_KIND = 336;
    uint256 internal constant UNAUTHORIZED_EXIT = 337;
    uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;
    uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;
    uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;
    uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;
    uint256 internal constant INVALID_INITIALIZATION = 342;
    uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;
    uint256 internal constant UNAUTHORIZED_OPERATION = 344;
    uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;

    // Lib
    uint256 internal constant REENTRANCY = 400;
    uint256 internal constant SENDER_NOT_ALLOWED = 401;
    uint256 internal constant PAUSED = 402;
    uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
    uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
    uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
    uint256 internal constant INSUFFICIENT_BALANCE = 406;
    uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
    uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
    uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
    uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
    uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
    uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
    uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
    uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
    uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
    uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
    uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
    uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
    uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
    uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
    uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
    uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
    uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;
    uint256 internal constant CALLER_IS_NOT_OWNER = 426;
    uint256 internal constant NEW_OWNER_IS_ZERO = 427;
    uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;
    uint256 internal constant CALL_TO_NON_CONTRACT = 429;
    uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;
    uint256 internal constant NOT_PAUSED = 431;
    uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;
    uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;
    uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434;

    // Vault
    uint256 internal constant INVALID_POOL_ID = 500;
    uint256 internal constant CALLER_NOT_POOL = 501;
    uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
    uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
    uint256 internal constant INVALID_SIGNATURE = 504;
    uint256 internal constant EXIT_BELOW_MIN = 505;
    uint256 internal constant JOIN_ABOVE_MAX = 506;
    uint256 internal constant SWAP_LIMIT = 507;
    uint256 internal constant SWAP_DEADLINE = 508;
    uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
    uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
    uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
    uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
    uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
    uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
    uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
    uint256 internal constant INSUFFICIENT_ETH = 516;
    uint256 internal constant UNALLOCATED_ETH = 517;
    uint256 internal constant ETH_TRANSFER = 518;
    uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
    uint256 internal constant TOKENS_MISMATCH = 520;
    uint256 internal constant TOKEN_NOT_REGISTERED = 521;
    uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
    uint256 internal constant TOKENS_ALREADY_SET = 523;
    uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
    uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
    uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
    uint256 internal constant POOL_NO_TOKENS = 527;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;

    // Fees
    uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
    uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/LogExpMath.sol


// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the “Software”), to deal in the
// Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// COPIED AND MODIFIED FROM:
// @balancer-v2-monorepo/pkg/solidity-utils/contracts/math/LogExpMath.sol
// XXX for changes

// XXX: 0.8.10; unchecked functions
pragma solidity 0.8.10;


/* solhint-disable */

/**
 * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
 *
 * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
 * exponentiation and logarithm (where the base is Euler's number).
 *
 * @author Fernando Martinelli - @fernandomartinelli
 * @author Sergio Yuhjtman - @sergioyuhjtman
 * @author Daniel Fernandez - @dmf7z
 */
library LogExpMath {
    // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
    // two numbers, and multiply by ONE when dividing them.

    // All arguments and return values are 18 decimal fixed point numbers.
    int256 constant ONE_18 = 1e18;

    // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
    // case of ln36, 36 decimals.
    int256 constant ONE_20 = 1e20;
    int256 constant ONE_36 = 1e36;

    // The domain of natural exponentiation is bound by the word size and number of decimals used.
    //
    // Because internally the result will be stored using 20 decimals, the largest possible result is
    // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
    // The smallest possible result is 10^(-18), which makes largest negative argument
    // ln(10^(-18)) = -41.446531673892822312.
    // We use 130.0 and -41.0 to have some safety margin.
    int256 constant MAX_NATURAL_EXPONENT = 130e18;
    int256 constant MIN_NATURAL_EXPONENT = -41e18;

    // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
    // 256 bit integer.
    int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
    int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;

    uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);

    // 18 decimal constants
    int256 constant x0 = 128000000000000000000; // 2ˆ7
    int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)
    int256 constant x1 = 64000000000000000000; // 2ˆ6
    int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)

    // 20 decimal constants
    int256 constant x2 = 3200000000000000000000; // 2ˆ5
    int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)
    int256 constant x3 = 1600000000000000000000; // 2ˆ4
    int256 constant a3 = 888611052050787263676000000; // eˆ(x3)
    int256 constant x4 = 800000000000000000000; // 2ˆ3
    int256 constant a4 = 298095798704172827474000; // eˆ(x4)
    int256 constant x5 = 400000000000000000000; // 2ˆ2
    int256 constant a5 = 5459815003314423907810; // eˆ(x5)
    int256 constant x6 = 200000000000000000000; // 2ˆ1
    int256 constant a6 = 738905609893065022723; // eˆ(x6)
    int256 constant x7 = 100000000000000000000; // 2ˆ0
    int256 constant a7 = 271828182845904523536; // eˆ(x7)
    int256 constant x8 = 50000000000000000000; // 2ˆ-1
    int256 constant a8 = 164872127070012814685; // eˆ(x8)
    int256 constant x9 = 25000000000000000000; // 2ˆ-2
    int256 constant a9 = 128402541668774148407; // eˆ(x9)
    int256 constant x10 = 12500000000000000000; // 2ˆ-3
    int256 constant a10 = 113314845306682631683; // eˆ(x10)
    int256 constant x11 = 6250000000000000000; // 2ˆ-4
    int256 constant a11 = 106449445891785942956; // eˆ(x11)

    /**
     * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
     *
     * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function pow(uint256 x, uint256 y) internal pure returns (uint256) {
        unchecked {
            if (y == 0) {
                // We solve the 0^0 indetermination by making it equal one.
                return uint256(ONE_18);
            }

            if (x == 0) {
                return 0;
            }

            // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
            // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
            // x^y = exp(y * ln(x)).

            // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
            _require(x < 2**255, Errors.X_OUT_OF_BOUNDS);
            int256 x_int256 = int256(x);

            // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
            // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.

            // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
            _require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS);
            int256 y_int256 = int256(y);

            int256 logx_times_y;
            if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
                int256 ln_36_x = _ln_36(x_int256);

                // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
                // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
                // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
                // (downscaled) last 18 decimals.
                logx_times_y = ((ln_36_x / ONE_18) *
                    y_int256 +
                    ((ln_36_x % ONE_18) * y_int256) /
                    ONE_18);
            } else {
                logx_times_y = _ln(x_int256) * y_int256;
            }
            logx_times_y /= ONE_18;

            // Finally, we compute exp(y * ln(x)) to arrive at x^y
            _require(
                MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,
                Errors.PRODUCT_OUT_OF_BOUNDS
            );

            return uint256(exp(logx_times_y));
        }
    }

    /**
     * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
     *
     * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function exp(int256 x) internal pure returns (int256) {
        _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT);

        unchecked {
            if (x < 0) {
                // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
                // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
                // Fixed point division requires multiplying by ONE_18.
                return ((ONE_18 * ONE_18) / exp(-x));
            }

            // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
            // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
            // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
            // decomposition.
            // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
            // decomposition, which will be lower than the smallest x_n.
            // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
            // We mutate x by subtracting x_n, making it the remainder of the decomposition.

            // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
            // intermediate overflows. Instead we store them as plain integers, with 0 decimals.
            // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
            // decomposition.

            // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
            // it and compute the accumulated product.

            int256 firstAN;
            if (x >= x0) {
                x -= x0;
                firstAN = a0;
            } else if (x >= x1) {
                x -= x1;
                firstAN = a1;
            } else {
                firstAN = 1; // One with no decimal places
            }

            // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
            // smaller terms.
            x *= 100;

            // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
            // one. Recall that fixed point multiplication requires dividing by ONE_20.
            int256 product = ONE_20;

            if (x >= x2) {
                x -= x2;
                product = (product * a2) / ONE_20;
            }
            if (x >= x3) {
                x -= x3;
                product = (product * a3) / ONE_20;
            }
            if (x >= x4) {
                x -= x4;
                product = (product * a4) / ONE_20;
            }
            if (x >= x5) {
                x -= x5;
                product = (product * a5) / ONE_20;
            }
            if (x >= x6) {
                x -= x6;
                product = (product * a6) / ONE_20;
            }
            if (x >= x7) {
                x -= x7;
                product = (product * a7) / ONE_20;
            }
            if (x >= x8) {
                x -= x8;
                product = (product * a8) / ONE_20;
            }
            if (x >= x9) {
                x -= x9;
                product = (product * a9) / ONE_20;
            }

            // x10 and x11 are unnecessary here since we have high enough precision already.

            // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
            // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).

            int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
            int256 term; // Each term in the sum, where the nth term is (x^n / n!).

            // The first term is simply x.
            term = x;
            seriesSum += term;

            // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
            // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.

            term = ((term * x) / ONE_20) / 2;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 3;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 4;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 5;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 6;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 7;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 8;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 9;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 10;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 11;
            seriesSum += term;

            term = ((term * x) / ONE_20) / 12;
            seriesSum += term;

            // 12 Taylor terms are sufficient for 18 decimal precision.

            // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
            // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
            // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
            // and then drop two digits to return an 18 decimal value.

            return (((product * seriesSum) / ONE_20) * firstAN) / 100;
        }
    }

    /**
     * @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.
     */
    function log(int256 arg, int256 base) internal pure returns (int256) {
        // This performs a simple base change: log(arg, base) = ln(arg) / ln(base).

        unchecked {
            // Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by
            // upscaling.

            int256 logBase;
            if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {
                logBase = _ln_36(base);
            } else {
                logBase = _ln(base) * ONE_18;
            }

            int256 logArg;
            if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {
                logArg = _ln_36(arg);
            } else {
                logArg = _ln(arg) * ONE_18;
            }

            // When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places
            return (logArg * ONE_18) / logBase;
        }
    }

    /**
     * @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function ln(int256 a) internal pure returns (int256) {
        // The real natural logarithm is not defined for negative numbers or zero.
        _require(a > 0, Errors.OUT_OF_BOUNDS);

        unchecked {
            if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {
                return _ln_36(a) / ONE_18;
            } else {
                return _ln(a);
            }
        }
    }

    /**
     * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function _ln(int256 a) private pure returns (int256) {
        unchecked {
            if (a < ONE_18) {
                // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
                // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
                // Fixed point division requires multiplying by ONE_18.
                return (-_ln((ONE_18 * ONE_18) / a));
            }

            // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
            // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
            // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
            // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
            // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
            // decomposition, which will be lower than the smallest a_n.
            // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
            // We mutate a by subtracting a_n, making it the remainder of the decomposition.

            // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
            // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
            // ONE_18 to convert them to fixed point.
            // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
            // by it and compute the accumulated sum.

            int256 sum = 0;
            if (a >= a0 * ONE_18) {
                a /= a0; // Integer, not fixed point division
                sum += x0;
            }

            if (a >= a1 * ONE_18) {
                a /= a1; // Integer, not fixed point division
                sum += x1;
            }

            // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
            sum *= 100;
            a *= 100;

            // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.

            if (a >= a2) {
                a = (a * ONE_20) / a2;
                sum += x2;
            }

            if (a >= a3) {
                a = (a * ONE_20) / a3;
                sum += x3;
            }

            if (a >= a4) {
                a = (a * ONE_20) / a4;
                sum += x4;
            }

            if (a >= a5) {
                a = (a * ONE_20) / a5;
                sum += x5;
            }

            if (a >= a6) {
                a = (a * ONE_20) / a6;
                sum += x6;
            }

            if (a >= a7) {
                a = (a * ONE_20) / a7;
                sum += x7;
            }

            if (a >= a8) {
                a = (a * ONE_20) / a8;
                sum += x8;
            }

            if (a >= a9) {
                a = (a * ONE_20) / a9;
                sum += x9;
            }

            if (a >= a10) {
                a = (a * ONE_20) / a10;
                sum += x10;
            }

            if (a >= a11) {
                a = (a * ONE_20) / a11;
                sum += x11;
            }

            // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
            // that converges rapidly for values of `a` close to one - the same one used in ln_36.
            // Let z = (a - 1) / (a + 1).
            // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

            // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
            // division by ONE_20.
            int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
            int256 z_squared = (z * z) / ONE_20;

            // num is the numerator of the series: the z^(2 * n + 1) term
            int256 num = z;

            // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
            int256 seriesSum = num;

            // In each step, the numerator is multiplied by z^2
            num = (num * z_squared) / ONE_20;
            seriesSum += num / 3;

            num = (num * z_squared) / ONE_20;
            seriesSum += num / 5;

            num = (num * z_squared) / ONE_20;
            seriesSum += num / 7;

            num = (num * z_squared) / ONE_20;
            seriesSum += num / 9;

            num = (num * z_squared) / ONE_20;
            seriesSum += num / 11;

            // 6 Taylor terms are sufficient for 36 decimal precision.

            // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
            seriesSum *= 2;

            // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
            // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
            // value.

            return (sum + seriesSum) / 100;
        }
    }

    /**
     * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
     * for x close to one.
     *
     * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
     */
    function _ln_36(int256 x) private pure returns (int256) {
        unchecked {
            // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
            // worthwhile.

            // First, we transform x to a 36 digit fixed point value.
            x *= ONE_18;

            // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
            // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

            // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
            // division by ONE_36.
            int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
            int256 z_squared = (z * z) / ONE_36;

            // num is the numerator of the series: the z^(2 * n + 1) term
            int256 num = z;

            // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
            int256 seriesSum = num;

            // In each step, the numerator is multiplied by z^2
            num = (num * z_squared) / ONE_36;
            seriesSum += num / 3;

            num = (num * z_squared) / ONE_36;
            seriesSum += num / 5;

            num = (num * z_squared) / ONE_36;
            seriesSum += num / 7;

            num = (num * z_squared) / ONE_36;
            seriesSum += num / 9;

            num = (num * z_squared) / ONE_36;
            seriesSum += num / 11;

            num = (num * z_squared) / ONE_36;
            seriesSum += num / 13;

            num = (num * z_squared) / ONE_36;
            seriesSum += num / 15;

            // 8 Taylor terms are sufficient for 36 decimal precision.

            // All that remains is multiplying by 2 (non fixed point).
            return seriesSum * 2;
        }
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/FixedPoint.sol


// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// COPIED AND MODIFIED FROM:
// @balancer-v2-monorepo/pkg/solidity-utils/contracts/math/FixedPoint.sol
// XXX for changes

// XXX: 0.8.10; removed requires for overflow checks
pragma solidity 0.8.10;


/* solhint-disable private-vars-leading-underscore */

library FixedPoint {
    uint256 internal constant ONE = 1e18; // 18 decimal places
    uint256 internal constant TWO = 2 * ONE;
    uint256 internal constant FOUR = 4 * ONE;
    uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14)

    // Minimum base for the power function when the exponent is 'free' (larger than ONE).
    uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18;

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        // Fixed Point addition is the same as regular checked addition
        uint256 c = a + b;
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        // Fixed Point addition is the same as regular checked addition
        uint256 c = a - b;
        return c;
    }

    /// @notice a - b but floors to zero if a <= b
    /// XXX: subFloor implementation
    function subFloor(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a > b ? a - b : 0;
        return c;
    }

    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 product = a * b;
        return product / ONE;
    }

    function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 product = a * b;
        if (product == 0) {
            return 0;
        } else {
            // The traditional divUp formula is:
            // divUp(x, y) := (x + y - 1) / y
            // To avoid intermediate overflow in the addition, we distribute the division and get:
            // divUp(x, y) := (x - 1) / y + 1
            // Note that this requires x != 0, which we already tested for.
            return ((product - 1) / ONE) + 1;
        }
    }

    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        } else {
            uint256 aInflated = a * ONE;
            return aInflated / b;
        }
    }

    function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        } else {
            uint256 aInflated = a * ONE;
            // The traditional divUp formula is:
            // divUp(x, y) := (x + y - 1) / y
            // To avoid intermediate overflow in the addition, we distribute the division and get:
            // divUp(x, y) := (x - 1) / y + 1
            // Note that this requires x != 0, which we already tested for.
            return ((aInflated - 1) / b) + 1;
        }
    }

    /**
     * @dev Returns x^y, assuming both are fixed point numbers, rounding down.
     * The result is guaranteed to not be above the true value (that is,
     * the error function expected - actual is always positive).
     */
    function powDown(uint256 x, uint256 y) internal pure returns (uint256) {
        // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple
        // to implement and occur often in 50/50 and 80/20 Weighted Pools
        // XXX: checks for y == 0, x == ONE, x == 0
        if (0 == y || x == ONE) {
            return ONE;
        } else if (x == 0) {
            return 0;
        } else if (y == ONE) {
            return x;
        } else if (y == TWO) {
            return mulDown(x, x);
        } else if (y == FOUR) {
            uint256 square = mulDown(x, x);
            return mulDown(square, square);
        } else {
            uint256 raw = LogExpMath.pow(x, y);
            uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

            if (raw < maxError) {
                return 0;
            } else {
                return sub(raw, maxError);
            }
        }
    }

    /**
     * @dev Returns x^y, assuming both are fixed point numbers, rounding up.
     * The result is guaranteed to not be below the true value (that is,
     * the error function expected - actual is always negative).
     */
    function powUp(uint256 x, uint256 y) internal pure returns (uint256) {
        // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple
        // to implement and occur often in 50/50 and 80/20 Weighted Pools
        // XXX: checks for y == 0, x == ONE, x == 0
        if (0 == y || x == ONE) {
            return ONE;
        } else if (x == 0) {
            return 0;
        } else if (y == ONE) {
            return x;
        } else if (y == TWO) {
            return mulUp(x, x);
        } else if (y == FOUR) {
            uint256 square = mulUp(x, x);
            return mulUp(square, square);
        } else {
            uint256 raw = LogExpMath.pow(x, y);
            uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

            return add(raw, maxError);
        }
    }

    /**
     * @dev Returns e^x, assuming x is a fixed point number, rounding down.
     * The result is guaranteed to not be above the true value (that is,
     * the error function expected - actual is always positive).
     * XXX: expDown implementation
     */
    function expDown(uint256 x) internal pure returns (uint256) {
        if (x == 0) {
            return ONE;
        }
        require(x < 2**255, "FixedPoint: x out of bounds");

        int256 x_int256 = int256(x);
        uint256 raw = uint256(LogExpMath.exp(x_int256));
        uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

        if (raw < maxError) {
            return 0;
        } else {
            return sub(raw, maxError);
        }
    }

    /**
     * @dev Returns e^x, assuming x is a fixed point number, rounding up.
     * The result is guaranteed to not be below the true value (that is,
     * the error function expected - actual is always negative).
     * XXX: expUp implementation
     */
    function expUp(uint256 x) internal pure returns (uint256) {
        if (x == 0) {
            return ONE;
        }
        require(x < 2**255, "FixedPoint: x out of bounds");

        int256 x_int256 = int256(x);
        uint256 raw = uint256(LogExpMath.exp(x_int256));
        uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

        return add(raw, maxError);
    }

    /**
     * @dev Returns log_b(a), assuming a, b are fixed point numbers, rounding down.
     * The result is guaranteed to not be above the true value (that is,
     * the error function expected - actual is always positive).
     * XXX: logDown implementation
     */
    function logDown(uint256 a, uint256 b) internal pure returns (int256) {
        require(a > 0 && a < 2**255, "FixedPoint: a out of bounds");
        require(b > 0 && b < 2**255, "FixedPoint: b out of bounds");

        int256 arg = int256(a);
        int256 base = int256(b);
        int256 raw = LogExpMath.log(arg, base);

        // NOTE: see @openzeppelin/contracts/utils/math/SignedMath.sol#L37
        uint256 rawAbs;
        unchecked {
            rawAbs = uint256(raw >= 0 ? raw : -raw);
        }
        uint256 maxError = add(mulUp(rawAbs, MAX_POW_RELATIVE_ERROR), 1);
        return raw - int256(maxError);
    }

    /**
     * @dev Returns log_b(a), assuming a, b are fixed point numbers, rounding up.
     * The result is guaranteed to not be below the true value (that is,
     * the error function expected - actual is always negative).
     * XXX: logUp implementation
     */
    function logUp(uint256 a, uint256 b) internal pure returns (int256) {
        require(a > 0 && a < 2**255, "FixedPoint: a out of bounds");
        require(b > 0 && b < 2**255, "FixedPoint: b out of bounds");

        int256 arg = int256(a);
        int256 base = int256(b);
        int256 raw = LogExpMath.log(arg, base);

        // NOTE: see @openzeppelin/contracts/utils/math/SignedMath.sol#L37
        uint256 rawAbs;
        unchecked {
            rawAbs = uint256(raw >= 0 ? raw : -raw);
        }
        uint256 maxError = add(mulUp(rawAbs, MAX_POW_RELATIVE_ERROR), 1);
        return raw + int256(maxError);
    }

    /**
     * @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1.
     *
     * Useful when computing the complement for values with some level of relative error,
     * as it strips this error and prevents intermediate negative values.
     */
    function complement(uint256 x) internal pure returns (uint256) {
        return (x < ONE) ? (ONE - x) : 0;
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/Cast.sol


pragma solidity 0.8.10;

library Cast {
    /// @dev casts an uint256 to an uint32 bounded by uint32 range of values
    /// @dev to avoid reverts and overflows
    function toUint32Bounded(uint256 value) internal pure returns (uint32) {
        uint32 value32 = (value <= type(uint32).max) ? uint32(value) : type(uint32).max;
        return value32;
    }

    /// @dev casts an int256 to an int192 bounded by int192 range of values
    /// @dev to avoid reverts and overflows
    function toInt192Bounded(int256 value) internal pure returns (int192) {
        int192 value192 = value < type(int192).min
            ? type(int192).min
            : (value > type(int192).max ? type(int192).max : int192(value));
        return value192;
    }
}

// File: @openzeppelin/contracts/utils/math/SignedMath.sol


// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a >= b ? a : b;
    }

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/Tick.sol


pragma solidity 0.8.10;



library Tick {
    using FixedPoint for uint256;
    using SignedMath for int256;

    uint256 internal constant ONE = 1e18;
    uint256 internal constant PRICE_BASE = 1.0001e18;
    int256 internal constant MAX_TICK_256 = 120e22;
    int256 internal constant MIN_TICK_256 = -41e22;

    /// @notice Computes the tick associated with the given price
    /// @notice where price = 1.0001 ** tick
    /// @dev FixedPoint lib constraints on min/max natural exponent of
    /// @dev -41e18, 130e18 respectively, means min/max tick will be
    /// @dev -41e18/ln(1.0001), 130e18/ln(1.0001), respectively (w some buffer)
    function priceToTick(uint256 price) internal pure returns (int24) {
        int256 tick256 = price.logDown(PRICE_BASE);
        require(tick256 >= MIN_TICK_256 && tick256 <= MAX_TICK_256, "OVLV1: tick out of bounds");

        // tick256 is FixedPoint format with 18 decimals. Divide by ONE
        // then truncate to int24
        return int24(tick256 / int256(ONE));
    }

    /// @notice Computes the price associated with the given tick
    /// @notice where price = 1.0001 ** tick
    /// @dev FixedPoint lib constraints on min/max natural exponent of
    /// @dev -41e18, 130e18 respectively, means min/max tick will be
    /// @dev -41e18/ln(1.0001), 130e18/ln(1.0001), respectively (w some buffer)
    function tickToPrice(int24 tick) internal pure returns (uint256) {
        // tick needs to be converted to Fixed point format with 18 decimals
        // to use FixedPoint powUp
        int256 tick256 = int256(tick) * int256(ONE);
        require(tick256 >= MIN_TICK_256 && tick256 <= MAX_TICK_256, "OVLV1: tick out of bounds");

        uint256 pow = uint256(tick256.abs());
        return (tick256 >= 0 ? PRICE_BASE.powDown(pow) : ONE.divDown(PRICE_BASE.powUp(pow)));
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/Roller.sol


pragma solidity 0.8.10;




library Roller {
    using Cast for uint256;
    using Cast for int256;
    using FixedPoint for uint256;
    using SignedMath for int256;

    struct Snapshot {
        uint32 timestamp; // time last snapshot was taken
        uint32 window; // window (length of time) over which will decay
        int192 accumulator; // accumulator value which will decay to zero over window
    }

    /// @dev returns the stored accumulator value as an int256
    function cumulative(Snapshot memory self) internal view returns (int256) {
        return int256(self.accumulator);
    }

    /// @dev adjusts accumulator value downward linearly over time.
    /// @dev accumulator should go to zero as one window passes
    function transform(
        Snapshot memory self,
        uint256 timestamp,
        uint256 window,
        int256 value
    ) internal view returns (Snapshot memory) {
        uint32 timestamp32 = uint32(timestamp); // truncated by compiler

        // int/uint256 values to use in calculations
        uint256 dt = timestamp32 >= self.timestamp
            ? uint256(timestamp32 - self.timestamp)
            : uint256(2**32) + uint256(timestamp32) - uint256(self.timestamp);
        uint256 snapWindow = uint256(self.window);
        int256 snapAccumulator = cumulative(self);

        if (dt >= snapWindow || snapWindow == 0) {
            // if one window has passed, prior value has decayed to zero
            return
                Snapshot({
                    timestamp: timestamp32,
                    window: window.toUint32Bounded(),
                    accumulator: value.toInt192Bounded()
                });
        }

        // otherwise, calculate fraction of value remaining given linear decay.
        // fraction of value to take off due to decay (linear drift toward zero)
        // is fraction of windowLast that has elapsed since timestampLast
        snapAccumulator = (snapAccumulator * int256(snapWindow - dt)) / int256(snapWindow);

        // add in the new value for accumulator now
        int256 accumulatorNow = snapAccumulator + value;
        if (accumulatorNow == 0) {
            // if accumulator now is zero, windowNow is simply window
            return
                Snapshot({
                    timestamp: timestamp32,
                    window: window.toUint32Bounded(),
                    accumulator: 0
                });
        }

        // recalculate windowNow_ for future decay as a value weighted average time
        // of time left in windowLast for accumulatorLast and window for value
        // vwat = (|accumulatorLastWithDecay| * (windowLast - dt) + |value| * window) /
        //        (|accumulatorLastWithDecay| + |value|)
        uint256 w1 = snapAccumulator.abs();
        uint256 w2 = value.abs();
        uint256 windowNow = (w1 * (snapWindow - dt) + w2 * window) / (w1 + w2);
        return
            Snapshot({
                timestamp: timestamp32,
                window: windowNow.toUint32Bounded(),
                accumulator: accumulatorNow.toInt192Bounded()
            });
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/Oracle.sol


pragma solidity 0.8.10;

library Oracle {
    struct Data {
        uint256 timestamp;
        uint256 microWindow;
        uint256 macroWindow;
        uint256 priceOverMicroWindow; // p(now) averaged over micro
        uint256 priceOverMacroWindow; // p(now) averaged over macro
        uint256 priceOneMacroWindowAgo; // p(now - macro) avg over macro
        uint256 reserveOverMicroWindow; // r(now) in ovl averaged over micro
        bool hasReserve; // whether oracle has manipulable reserve pool
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/interfaces/feeds/IOverlayV1Feed.sol


pragma solidity 0.8.10;


interface IOverlayV1Feed {
    // immutables
    function feedFactory() external view returns (address);

    function microWindow() external view returns (uint256);

    function macroWindow() external view returns (uint256);

    // returns freshest possible data from oracle
    function latest() external view returns (Oracle.Data memory);
}

// File: @openzeppelin/contracts/access/IAccessControl.sol


// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// File: @openzeppelin/contracts/access/IAccessControlEnumerable.sol


// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)

pragma solidity ^0.8.0;


/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol


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

pragma solidity ^0.8.0;

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

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/interfaces/IOverlayV1Token.sol


pragma solidity 0.8.10;



bytes32 constant MINTER_ROLE = keccak256("MINTER");
bytes32 constant BURNER_ROLE = keccak256("BURNER");
bytes32 constant GOVERNOR_ROLE = keccak256("GOVERNOR");
bytes32 constant GUARDIAN_ROLE = keccak256("GUARDIAN");

interface IOverlayV1Token is IAccessControlEnumerable, IERC20 {
    // mint/burn
    function mint(address _recipient, uint256 _amount) external;

    function burn(uint256 _amount) external;
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/interfaces/IOverlayV1Deployer.sol


pragma solidity 0.8.10;

interface IOverlayV1Deployer {
    function factory() external view returns (address);

    function ovl() external view returns (address);

    function deploy(address feed) external returns (address);

    function parameters()
        external
        view
        returns (
            address ovl_,
            address feed_,
            address factory_
        );
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/Risk.sol


pragma solidity 0.8.10;

library Risk {
    enum Parameters {
        K, // funding constant
        Lmbda, // market impact constant
        Delta, // bid-ask static spread constant
        CapPayoff, // payoff cap
        CapNotional, // initial notional cap
        CapLeverage, // initial leverage cap
        CircuitBreakerWindow, // trailing window for circuit breaker
        CircuitBreakerMintTarget, // target worst case inflation rate over trailing window
        MaintenanceMarginFraction, // maintenance margin (mm) constant
        MaintenanceMarginBurnRate, // burn rate for mm constant
        LiquidationFeeRate, // liquidation fee charged on liquidate
        TradingFeeRate, // trading fee charged on build/unwind
        MinCollateral, // minimum ovl collateral to open position
        PriceDriftUpperLimit, // upper limit for feed price changes since last update
        AverageBlockTime // average block time of the respective chain
    }

    /// @notice Gets the value associated with the given parameter type
    function get(uint256[15] storage self, Parameters name) internal view returns (uint256) {
        return self[uint256(name)];
    }

    /// @notice Sets the value associated with the given parameter type
    function set(
        uint256[15] storage self,
        Parameters name,
        uint256 value
    ) internal {
        self[uint256(name)] = value;
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/interfaces/IOverlayV1Market.sol


pragma solidity 0.8.10;





interface IOverlayV1Market {
    // immutables
    function ovl() external view returns (IOverlayV1Token);

    function feed() external view returns (address);

    function factory() external view returns (address);

    // risk params
    function params(uint256 idx) external view returns (uint256);

    // oi related quantities
    function oiLong() external view returns (uint256);

    function oiShort() external view returns (uint256);

    function oiLongShares() external view returns (uint256);

    function oiShortShares() external view returns (uint256);

    // rollers
    function snapshotVolumeBid()
        external
        view
        returns (
            uint32 timestamp_,
            uint32 window_,
            int192 accumulator_
        );

    function snapshotVolumeAsk()
        external
        view
        returns (
            uint32 timestamp_,
            uint32 window_,
            int192 accumulator_
        );

    function snapshotMinted()
        external
        view
        returns (
            uint32 timestamp_,
            uint32 window_,
            int192 accumulator_
        );

    // positions
    function positions(bytes32 key)
        external
        view
        returns (
            uint96 notionalInitial_,
            uint96 debtInitial_,
            int24 midTick_,
            int24 entryTick_,
            bool isLong_,
            bool liquidated_,
            uint240 oiShares_,
            uint16 fractionRemaining_
        );

    // update related quantities
    function timestampUpdateLast() external view returns (uint256);

    // cached risk calcs
    function dpUpperLimit() external view returns (uint256);

    // emergency shutdown
    function isShutdown() external view returns (bool);

    // initializes market
    function initialize(uint256[15] memory params) external;

    // position altering functions
    function build(
        uint256 collateral,
        uint256 leverage,
        bool isLong,
        uint256 priceLimit
    ) external returns (uint256 positionId_);

    function unwind(
        uint256 positionId,
        uint256 fraction,
        uint256 priceLimit
    ) external;

    function liquidate(address owner, uint256 positionId) external;

    // updates market
    function update() external returns (Oracle.Data memory);

    // sanity check on data fetched from oracle in case of manipulation
    function dataIsValid(Oracle.Data memory) external view returns (bool);

    // current open interest after funding payments transferred
    function oiAfterFunding(
        uint256 oiOverweight,
        uint256 oiUnderweight,
        uint256 timeElapsed
    ) external view returns (uint256 oiOverweight_, uint256 oiUnderweight_);

    // current open interest cap with adjustments for circuit breaker if market has
    // printed a lot in recent past
    function capOiAdjustedForCircuitBreaker(uint256 cap) external view returns (uint256);

    // bound on open interest cap from circuit breaker
    function circuitBreaker(Roller.Snapshot memory snapshot, uint256 cap)
        external
        view
        returns (uint256);

    // current notional cap with adjustments to prevent front-running
    // trade and back-running trade
    function capNotionalAdjustedForBounds(Oracle.Data memory data, uint256 cap)
        external
        view
        returns (uint256);

    // bound on open interest cap to mitigate front-running attack
    function frontRunBound(Oracle.Data memory data) external view returns (uint256);

    // bound on open interest cap to mitigate back-running attack
    function backRunBound(Oracle.Data memory data) external view returns (uint256);

    // transforms notional into number of contracts (open interest)
    function oiFromNotional(uint256 notional, uint256 midPrice) external view returns (uint256);

    // bid price given oracle data and recent volume
    function bid(Oracle.Data memory data, uint256 volume) external view returns (uint256 bid_);

    // ask price given oracle data and recent volume
    function ask(Oracle.Data memory data, uint256 volume) external view returns (uint256 ask_);

    // risk parameter setter
    function setRiskParam(Risk.Parameters name, uint256 value) external;

    // emergency shutdown market
    function shutdown() external;

    // emergency withdraw collateral after shutdown
    function emergencyWithdraw(uint256 positionId) external;
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/interfaces/IOverlayV1Factory.sol


pragma solidity 0.8.10;




interface IOverlayV1Factory {
    // risk param bounds
    function PARAMS_MIN(uint256 idx) external view returns (uint256);

    function PARAMS_MAX(uint256 idx) external view returns (uint256);

    // immutables
    function ovl() external view returns (IOverlayV1Token);

    function deployer() external view returns (IOverlayV1Deployer);

    // global parameter
    function feeRecipient() external view returns (address);

    // registry of supported feed factories
    function isFeedFactory(address feedFactory) external view returns (bool);

    // registry of markets; for a given feed address, returns associated market
    function getMarket(address feed) external view returns (address market_);

    // registry of deployed markets by factory
    function isMarket(address market) external view returns (bool);

    // adding feed factory to allowed feed types
    function addFeedFactory(address feedFactory) external;

    // removing feed factory from allowed feed types
    function removeFeedFactory(address feedFactory) external;

    // deploy new market
    function deployMarket(
        address feedFactory,
        address feed,
        uint256[15] calldata params
    ) external returns (address market_);

    // per-market risk parameter setters
    function setRiskParam(
        address feed,
        Risk.Parameters name,
        uint256 value
    ) external;

    // fee repository setter
    function setFeeRecipient(address _feeRecipient) external;
}

// File: @openzeppelin/contracts/utils/math/Math.sol


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

pragma solidity ^0.8.0;

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

            ///////////////////////////////////////////////
            // 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. It 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)`.
        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
        // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
        // good first aproximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1;
        uint256 x = a;
        if (x >> 128 > 0) {
            x >>= 128;
            result <<= 64;
        }
        if (x >> 64 > 0) {
            x >>= 64;
            result <<= 32;
        }
        if (x >> 32 > 0) {
            x >>= 32;
            result <<= 16;
        }
        if (x >> 16 > 0) {
            x >>= 16;
            result <<= 8;
        }
        if (x >> 8 > 0) {
            x >>= 8;
            result <<= 4;
        }
        if (x >> 4 > 0) {
            x >>= 4;
            result <<= 2;
        }
        if (x >> 2 > 0) {
            result <<= 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) {
        uint256 result = sqrt(a);
        if (rounding == Rounding.Up && result * result < a) {
            result += 1;
        }
        return result;
    }
}

// File: https://github.com/overlay-market/v1-core/blob/main/contracts/libraries/Position.sol


pragma solidity 0.8.10;






library Position {
    using FixedCast for uint16;
    using FixedCast for uint256;
    using FixedPoint for uint256;

    uint256 internal constant ONE = 1e18;

    /// @dev immutables: notionalInitial, debtInitial, midTick, entryTick, isLong
    /// @dev mutables: liquidated, oiShares, fractionRemaining
    struct Info {
        uint96 notionalInitial; // initial notional = collateral * leverage
        uint96 debtInitial; // initial debt = notional - collateral
        int24 midTick; // midPrice = 1.0001 ** midTick at build
        int24 entryTick; // entryPrice = 1.0001 ** entryTick at build
        bool isLong; // whether long or short
        bool liquidated; // whether has been liquidated (mutable)
        uint240 oiShares; // current shares of aggregate open interest on side (mutable)
        uint16 fractionRemaining; // fraction of initial position remaining (mutable)
    }

    /*///////////////////////////////////////////////////////////////
                        POSITIONS MAPPING FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Retrieves a position from positions mapping
    function get(
        mapping(bytes32 => Info) storage self,
        address owner,
        uint256 id
    ) internal view returns (Info memory position_) {
        position_ = self[keccak256(abi.encodePacked(owner, id))];
    }

    /// @notice Stores a position in positions mapping
    function set(
        mapping(bytes32 => Info) storage self,
        address owner,
        uint256 id,
        Info memory position
    ) internal {
        self[keccak256(abi.encodePacked(owner, id))] = position;
    }

    /*///////////////////////////////////////////////////////////////
                    POSITION CAST GETTER FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Computes the position's initial notional cast to uint256
    function _notionalInitial(Info memory self) private pure returns (uint256) {
        return uint256(self.notionalInitial);
    }

    /// @notice Computes the position's initial debt cast to uint256
    function _debtInitial(Info memory self) private pure returns (uint256) {
        return uint256(self.debtInitial);
    }

    /// @notice Computes the position's current shares of open interest
    /// @notice cast to uint256
    function _oiShares(Info memory self) private pure returns (uint256) {
        return uint256(self.oiShares);
    }

    /// @notice Computes the fraction remaining of the position cast to uint256
    function _fractionRemaining(Info memory self) private pure returns (uint256) {
        return self.fractionRemaining.toUint256Fixed();
    }

    /*///////////////////////////////////////////////////////////////
                     POSITION EXISTENCE FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Whether the position exists
    /// @dev Is false if position has been liquidated or fraction remaining == 0
    function exists(Info memory self) internal pure returns (bool exists_) {
        return (!self.liquidated && self.fractionRemaining > 0);
    }

    /*///////////////////////////////////////////////////////////////
                 POSITION FRACTION REMAINING FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Gets the current fraction remaining of the initial position
    function getFractionRemaining(Info memory self) internal pure returns (uint256) {
        return _fractionRemaining(self);
    }

    /// @notice Computes an updated fraction remaining of the initial position
    /// @notice given fractionRemoved unwound/liquidated from remaining position
    function updatedFractionRemaining(Info memory self, uint256 fractionRemoved)
        internal
        pure
        returns (uint16)
    {
        require(fractionRemoved <= ONE, "OVLV1:fraction>max");
        uint256 fractionRemaining = _fractionRemaining(self).mulDown(ONE - fractionRemoved);
        return fractionRemaining.toUint16Fixed();
    }

    /*///////////////////////////////////////////////////////////////
                      POSITION PRICE FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Computes the midPrice of the position at entry cast to uint256
    /// @dev Will be slightly different (tol of 1bps) vs actual
    /// @dev midPrice at build given tick resolution limited to 1bps
    /// @dev Only affects value() calc below and thus PnL slightly
    function midPriceAtEntry(Info memory self) internal pure returns (uint256 midPrice_) {
        midPrice_ = Tick.tickToPrice(self.midTick);
    }

    /// @notice Computes the entryPrice of the position cast to uint256
    /// @dev Will be slightly different (tol of 1bps) vs actual
    /// @dev entryPrice at build given tick resolution limited to 1bps
    /// @dev Only affects value() calc below and thus PnL slightly
    function entryPrice(Info memory self) internal pure returns (uint256 entryPrice_) {
        entryPrice_ = Tick.tickToPrice(self.entryTick);
    }

    /*///////////////////////////////////////////////////////////////
                         POSITION OI FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Computes the amount of shares of open interest to issue
    /// @notice a newly built position
    /// @dev use mulDiv
    function calcOiShares(
        uint256 oi,
        uint256 oiTotalOnSide,
        uint256 oiTotalSharesOnSide
    ) internal pure returns (uint256 oiShares_) {
        oiShares_ = (oiTotalOnSide == 0 || oiTotalSharesOnSide == 0)
            ? oi
            : FullMath.mulDiv(oi, oiTotalSharesOnSide, oiTotalOnSide);
    }

    /// @notice Computes the position's initial open interest cast to uint256
    /// @dev oiInitial = Q / midPriceAtEntry
    /// @dev Will be slightly different (tol of 1bps) vs actual oi at build
    /// @dev given midTick resolution limited to 1bps
    /// @dev Only affects value() calc below and thus PnL slightly
    function _oiInitial(Info memory self) private pure returns (uint256) {
        uint256 q = _notionalInitial(self);
        uint256 mid = midPriceAtEntry(self);
        return q.divDown(mid);
    }

    /*///////////////////////////////////////////////////////////////
                POSITION FRACTIONAL GETTER FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Computes the initial notional of position when built
    /// @notice accounting for amount of position remaining
    /// @dev use mulUp to avoid rounding leftovers on unwind
    function notionalInitial(Info memory self, uint256 fraction) internal pure returns (uint256) {
        uint256 fractionRemaining = _fractionRemaining(self);
        uint256 notionalForRemaining = _notionalInitial(self).mulUp(fractionRemaining);
        return notionalForRemaining.mulUp(fraction);
    }

    /// @notice Computes the initial open interest of position when built
    /// @notice accounting for amount of position remaining
    /// @dev use mulUp to avoid rounding leftovers on unwind
    function oiInitial(Info memory self, uint256 fraction) internal pure returns (uint256) {
        uint256 fractionRemaining = _fractionRemaining(self);
        uint256 oiInitialForRemaining = _oiInitial(self).mulUp(fractionRemaining);
        return oiInitialForRemaining.mulUp(fraction);
    }

    /// @notice Computes the current shares of open interest position holds
    /// @notice on pos.isLong side of the market
    /// @dev use mulDown to avoid giving excess shares to pos owner on unwind
    function oiSharesCurrent(Info memory self, uint256 fraction) internal pure returns (uint256) {
        uint256 oiSharesForRemaining = _oiShares(self);
        // WARNING: must mulDown to avoid giving excess oi shares
        return oiSharesForRemaining.mulDown(fraction);
    }

    /// @notice Computes the current debt position holds accounting
    /// @notice for amount of position remaining
    /// @dev use mulUp to avoid rounding leftovers on unwind
    function debtInitial(Info memory self, uint256 fraction) internal pure returns (uint256) {
        uint256 fractionRemaining = _fractionRemaining(self);
        uint256 debtForRemaining = _debtInitial(self).mulUp(fractionRemaining);
        return debtForRemaining.mulUp(fraction);
    }

    /// @notice Computes the current open interest of remaining position accounting for
    /// @notice potential funding payments between long/short sides
    /// @dev returns zero when oiShares = oiTotalOnSide = oiTotalSharesOnSide = 0 to avoid
    /// @dev div by zero errors
    /// @dev use mulDiv
    function oiCurrent(
        Info memory self,
        uint256 fraction,
        uint256 oiTotalOnSide,
        uint256 oiTotalSharesOnSide
    ) internal pure returns (uint256) {
        uint256 oiShares = oiSharesCurrent(self, fraction);
        if (oiShares == 0 || oiTotalOnSide == 0 || oiTotalSharesOnSide == 0) return 0;
        return FullMath.mulDiv(oiShares, oiTotalOnSide, oiTotalSharesOnSide);
    }

    /// @notice Computes the remaining position's cost cast to uint256
    function cost(Info memory self, uint256 fraction) internal pure returns (uint256) {
        uint256 posNotionalInitial = notionalInitial(self, fraction);
        uint256 posDebt = debtInitial(self, fraction);

        // should always be > 0 but use subFloor to be safe w reverts
        uint256 posCost = posNotionalInitial;
        posCost = posCost.subFloor(posDebt);
        return posCost;
    }

    /*///////////////////////////////////////////////////////////////
                        POSITION CALC FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /// @notice Computes the value of remaining position
    /// @dev Floors to zero, so won't properly compute if self is underwater
    function value(
        Info memory self,
        uint256 fraction,
        uint256 oiTotalOnSide,
        uint256 oiTotalSharesOnSide,
        uint256 currentPrice,
        uint256 capPayoff
    ) internal pure returns (uint256 val_) {
        uint256 posOiInitial = oiInitial(self, fraction);
        uint256 posNotionalInitial = notionalInitial(self, fraction);
        uint256 posDebt = debtInitial(self, fraction);

        uint256 posOiCurrent = oiCurrent(self, fraction, oiTotalOnSide, oiTotalSharesOnSide);
        uint256 posEntryPrice = entryPrice(self);

        // NOTE: PnL = +/- oiCurrent * [currentPrice - entryPrice]; ... (w/o capPayoff)
        // NOTE: fundingPayments = notionalInitial * ( oiCurrent / oiInitial - 1 )
        // NOTE: value = collateralInitial + PnL + fundingPayments
        // NOTE:       = notionalInitial - debt + PnL + fundingPayments
        if (self.isLong) {
            // val = notionalInitial * oiCurrent / oiInitial
            //       + oiCurrent * min[currentPrice, entryPrice * (1 + capPayoff)]
            //       - oiCurrent * entryPrice - debt
            val_ =
                posNotionalInitial.mulUp(posOiCurrent).divUp(posOiInitial) +
                Math.min(
                    posOiCurrent.mulUp(currentPrice),
                    posOiCurrent.mulUp(posEntryPrice).mulUp(ONE + capPayoff)
                );
            // floor to 0
            val_ = val_.subFloor(posDebt + posOiCurrent.mulUp(posEntryPrice));
        } else {
            // NOTE: capPayoff >= 1, so no need to include w short
            // val = notionalInitial * oiCurrent / oiInitial + oiCurrent * entryPrice
            //       - oiCurrent * currentPrice - debt
            val_ =
                posNotionalInitial.mulUp(posOiCurrent).divUp(posOiInitial) +
                posOiCurrent.mulUp(posEntryPrice);
            // floor to 0
            val_ = val_.subFloor(posDebt + posOiCurrent.mulUp(currentPrice));
        }
    }

    /// @notice Computes the current notional of remaining position including PnL
    /// @dev Floors to debt if value <= 0
    function notionalWithPnl(
        Info memory self,
        uint256 fraction,
        uint256 oiTotalOnSide,
        uint256 oiTotalSharesOnSide,
        uint256 currentPrice,
        uint256 capPayoff
    ) internal pure returns (uint256 notionalWithPnl_) {
        uint256 posValue = value(
            self,
            fraction,
            oiTotalOnSide,
            oiTotalSharesOnSide,
            currentPrice,
            capPayoff
        );
        uint256 posDebt = debtInitial(self, fraction);
        notionalWithPnl_ = posValue + posDebt;
    }

    /// @notice Computes the trading fees to be imposed on remaining position
    /// @notice for build/unwind
    function tradingFee(
        Info memory self,
        uint256 fraction,
        uint256 oiTotalOnSide,
        uint256 oiTotalSharesOnSide,
        uint256 currentPrice,
        uint256 capPayoff,
        uint256 tradingFeeRate
    ) internal pure returns (uint256 tradingFee_) {
        uint256 posNotional = notionalWithPnl(
            self,
            fraction,
            oiTotalOnSide,
            oiTotalSharesOnSide,
            currentPrice,
            capPayoff
        );
        tradingFee_ = posNotional.mulUp(tradingFeeRate);
    }

    /// @notice Whether a position can be liquidated
    /// @dev is true when value * (1 - liq fee rate) < maintenance margin
    /// @dev liq fees are reward given to liquidator
    function liquidatable(
        Info memory self,
        uint256 oiTotalOnSide,
        uint256 oiTotalSharesOnSide,
        uint256 currentPrice,
        uint256 capPayoff,
        uint256 maintenanceMarginFraction,
        uint256 liquidationFeeRate
    ) internal pure returns (bool can_) {
        uint256 fraction = ONE;
        uint256 posNotionalInitial = notionalInitial(self, fraction);

        if (self.liquidated || self.fractionRemaining == 0) {
            // already been liquidated or doesn't exist
            // latter covers edge case of val == 0 and MM + liq fee == 0
            return false;
        }

        uint256 val = value(
            self,
            fraction,
            oiTotalOnSide,
            oiTotalSharesOnSide,
            currentPrice,
            capPayoff
        );
        uint256 maintenanceMargin = posNotionalInitial.mulUp(maintenanceMarginFraction);
        uint256 liquidationFee = val.mulDown(liquidationFeeRate);
        can_ = val < maintenanceMargin + liquidationFee;
    }
}

// File: github/overlay-market/v1-core/contracts/OverlayV1Market.sol


pragma solidity 0.8.10;













contract OverlayV1Market is IOverlayV1Market {
    using FixedCast for uint16;
    using FixedCast for uint256;
    using FixedPoint for uint256;
    using Oracle for Oracle.Data;
    using Position for mapping(bytes32 => Position.Info);
    using Position for Position.Info;
    using Risk for uint256[15];
    using Roller for Roller.Snapshot;

    // internal constants
    uint256 internal constant ONE = 1e18; // 18 decimal places

    // cap for euler exponent powers; SEE: ./libraries/LogExpMath.sol::pow
    // using ~ 1/2 library max for substantial padding
    uint256 internal constant MAX_NATURAL_EXPONENT = 20e18;

    // immutables
    IOverlayV1Token public immutable ovl; // ovl token
    address public immutable feed; // oracle feed
    address public immutable factory; // factory that deployed this market

    // risk params
    uint256[15] public params; // params.idx order based on Risk.Parameters enum

    // aggregate oi quantities
    uint256 public oiLong;
    uint256 public oiShort;
    uint256 public oiLongShares;
    uint256 public oiShortShares;

    // rollers
    Roller.Snapshot public override snapshotVolumeBid; // snapshot of recent volume on bid
    Roller.Snapshot public override snapshotVolumeAsk; // snapshot of recent volume on ask
    Roller.Snapshot public override snapshotMinted; // snapshot of recent PnL minted/burned

    // positions
    mapping(bytes32 => Position.Info) public override positions;
    uint256 private _totalPositions;

    // data from last call to update
    uint256 public timestampUpdateLast;

    // cached risk calcs
    uint256 public dpUpperLimit; // e**(+priceDriftUpperLimit * macroWindow)

    // emergency shutdown
    bool public isShutdown;

    // factory modifier for governance sensitive functions
    modifier onlyFactory() {
        require(msg.sender == factory, "OVLV1: !factory");
        _;
    }

    // not shutdown modifier for regular functionality
    modifier notShutdown() {
        require(!isShutdown, "OVLV1: shutdown");
        _;
    }

    // shutdown modifier for emergencies
    modifier hasShutdown() {
        require(isShutdown, "OVLV1: !shutdown");
        _;
    }

    // events for core functions
    event Build(
        address indexed sender, // address that initiated build (owns position)
        uint256 positionId, // id of built position
        uint256 oi, // oi of position at build
        uint256 debt, // debt of position at build
        bool isLong, // whether is long or short
        uint256 price // entry price
    );
    event Unwind(
        address indexed sender, // address that initiated unwind (owns position)
        uint256 positionId, // id of unwound position
        uint256 fraction, // fraction of position unwound
        int256 mint, // total amount minted/burned (+/-) at unwind
        uint256 price // exit price
    );
    event Liquidate(
        address indexed sender, // address that initiated liquidate
        address indexed owner, // address that owned the liquidated position
        uint256 positionId, // id of the liquidated position
        int256 mint, // total amount burned (-) at liquidate
        uint256 price // liquidation price
    );
    event EmergencyWithdraw(
        address indexed sender, // address that initiated withdraw (owns position)
        uint256 positionId, // id of withdrawn position
        uint256 collateral // total amount of collateral withdrawn
    );

    constructor() {
        (address _ovl, address _feed, address _factory) = IOverlayV1Deployer(msg.sender)
            .parameters();
        ovl = IOverlayV1Token(_ovl);
        feed = _feed;
        factory = _factory;
    }

    /// @notice initializes the market and its risk params
    /// @notice called only once by factory on deployment
    function initialize(uint256[15] memory _params) external onlyFactory {
        // initialize update data
        Oracle.Data memory data = IOverlayV1Feed(feed).latest();
        require(_midFromFeed(data) > 0, "OVLV1:!data");
        timestampUpdateLast = block.timestamp;

        // check risk params valid
        uint256 _capLeverage = _params[uint256(Risk.Parameters.CapLeverage)];
        uint256 _delta = _params[uint256(Risk.Parameters.Delta)];
        uint256 _maintenanceMarginFraction = _params[
            uint256(Risk.Parameters.MaintenanceMarginFraction)
        ];
        uint256 _liquidationFeeRate = _params[uint256(Risk.Parameters.LiquidationFeeRate)];
        require(
            _capLeverage <=
                ONE.divDown(
                    2 * _delta + _maintenanceMarginFraction.divDown(ONE - _liquidationFeeRate)
                ),
            "OVLV1: max lev immediately liquidatable"
        );

        uint256 _priceDriftUpperLimit = _params[uint256(Risk.Parameters.PriceDriftUpperLimit)];
        require(
            _priceDriftUpperLimit * data.macroWindow < MAX_NATURAL_EXPONENT,
            "OVLV1: price drift exceeds max exp"
        );
        _cacheRiskCalc(Risk.Parameters.PriceDriftUpperLimit, _priceDriftUpperLimit);

        // set the risk params
        for (uint256 i = 0; i < _params.length; i++) {
            params[i] = _params[i];
        }
    }

    /// @dev builds a new position
    function build(
        uint256 collateral,
        uint256 leverage,
        bool isLong,
        uint256 priceLimit
    ) external notShutdown returns (uint256 positionId_) {
        require(leverage >= ONE, "OVLV1:lev<min");
        require(leverage <= params.get(Risk.Parameters.CapLeverage), "OVLV1:lev>max");
        require(collateral >= params.get(Risk.Parameters.MinCollateral), "OVLV1:collateral<min");

        uint256 oi;
        uint256 debt;
        uint256 price;
        uint256 tradingFee;
        // avoids stack too deep
        {
            // call to update before any effects
            Oracle.Data memory data = update();

            // calculate notional, oi, and trading fees. fees charged on notional
            // and added to collateral transferred in
            uint256 notional = collateral.mulUp(leverage);
            uint256 midPrice = _midFromFeed(data);
            oi = oiFromNotional(notional, midPrice);

            // check have more than zero number of contracts built
            require(oi > 0, "OVLV1:oi==0");

            // calculate debt and trading fees. fees charged on notional
            // and added to collateral transferred in
            debt = notional - collateral;
            tradingFee = notional.mulUp(params.get(Risk.Parameters.TradingFeeRate));

            // calculate current notional cap adjusted for front run
            // and back run bounds. transform into a cap on open interest
            uint256 capOi = oiFromNotional(
                capNotionalAdjustedForBounds(data, params.get(Risk.Parameters.CapNotional)),
                midPrice
            );

            // longs get the ask and shorts get the bid on build
            // register the additional volume on either the ask or bid
            // where volume = oi / capOi
            price = isLong
                ? ask(data, _registerVolumeAsk(data, oi, capOi))
                : bid(data, _registerVolumeBid(data, oi, capOi));
            // check price hasn't changed more than max slippage specified by trader
            require(isLong ? price <= priceLimit : price >= priceLimit, "OVLV1:slippage>max");

            // add new position's open interest to the side's aggregate oi value
            // and increase number of oi shares issued
            uint256 oiShares = _addToOiAggregates(oi, capOi, isLong);

            // assemble position info data
            // check position is not immediately liquidatable prior to storing
            Position.Info memory pos = Position.Info({
                notionalInitial: uint96(notional), // won't overflow as capNotional max is 8e24
                debtInitial: uint96(debt),
                midTick: Tick.priceToTick(midPrice),
                entryTick: Tick.priceToTick(price),
                isLong: isLong,
                liquidated: false,
                oiShares: uint240(oiShares), // won't overflow as oiShares ~ notional/mid
                fractionRemaining: ONE.toUint16Fixed()
            });
            require(
                !pos.liquidatable(
                    isLong ? oiLong : oiShort,
                    isLong ? oiLongShares : oiShortShares,
                    midPrice, // mid price used on liquidations
                    params.get(Risk.Parameters.CapPayoff),
                    params.get(Risk.Parameters.MaintenanceMarginFraction),
                    params.get(Risk.Parameters.LiquidationFeeRate)
                ),
                "OVLV1:liquidatable"
            );

            // store the position info data
            positionId_ = _totalPositions;
            positions.set(msg.sender, positionId_, pos);
            _totalPositions++;
        }

        // emit build event
        emit Build(msg.sender, positionId_, oi, debt, isLong, price);

        // transfer in the OVL collateral needed to back the position + fees
        // trading fees charged as a percentage on notional size of position
        ovl.transferFrom(msg.sender, address(this), collateral + tradingFee);

        // send trading fees to trading fee recipient
        ovl.transfer(IOverlayV1Factory(factory).feeRecipient(), tradingFee);
    }

    /// @dev unwinds fraction of an existing position
    function unwind(
        uint256 positionId,
        uint256 fraction,
        uint256 priceLimit
    ) external notShutdown {
        require(fraction <= ONE, "OVLV1:fraction>max");
        // only keep 4 decimal precision (1 bps) for fraction given
        // pos.fractionRemaining only to 4 decimals
        fraction = fraction.toUint16Fixed().toUint256Fixed();
        require(fraction > 0, "OVLV1:fraction<min");

        uint256 value;
        uint256 cost;
        uint256 price;
        uint256 tradingFee;
        // avoids stack too deep
        {
            // call to update before any effects
            Oracle.Data memory data = update();

            // check position exists
            Position.Info memory pos = positions.get(msg.sender, positionId);
            require(pos.exists(), "OVLV1:!position");

            // cache for gas savings
            uint256 oiTotalOnSide = pos.isLong ? oiLong : oiShort;
            uint256 oiTotalSharesOnSide = pos.isLong ? oiLongShares : oiShortShares;

            // check position not liquidatable otherwise can't unwind
            require(
                !pos.liquidatable(
                    oiTotalOnSide,
                    oiTotalSharesOnSide,
                    _midFromFeed(data), // mid price used on liquidations
                    params.get(Risk.Parameters.CapPayoff),
                    params.get(Risk.Parameters.MaintenanceMarginFraction),
                    params.get(Risk.Parameters.LiquidationFeeRate)
                ),
                "OVLV1:liquidatable"
            );

            // longs get the bid and shorts get the ask on unwind
            // register the additional volume on either the ask or bid
            // where volume = oi / capOi
            // current cap only adjusted for bounds (no circuit breaker so traders
            // don't get stuck in a position)
            uint256 capOi = oiFromNotional(
                capNotionalAdjustedForBounds(data, params.get(Risk.Parameters.CapNotional)),
                _midFromFeed(data)
            );
            price = pos.isLong
                ? bid(
                    data,
                    _registerVolumeBid(
                        data,
                        pos.oiCurrent(fraction, oiTotalOnSide, oiTotalSharesOnSide),
                        capOi
                    )
                )
                : ask(
                    data,
                    _registerVolumeAsk(
                        data,
                        pos.oiCurrent(fraction, oiTotalOnSide, oiTotalSharesOnSide),
                        capOi
                    )
                );
            // check price hasn't changed more than max slippage specified by trader
            require(pos.isLong ? price >= priceLimit : price <= priceLimit, "OVLV1:slippage>max");

            // calculate the value and cost of the position for pnl determinations
            // and amount to transfer
            uint256 capPayoff = params.get(Risk.Parameters.CapPayoff);
            value = pos.value(fraction, oiTotalOnSide, oiTotalSharesOnSide, price, capPayoff);
            cost = pos.cost(fraction);

            // calculate the trading fee as % on notional
            uint256 tradingFeeRate = params.get(Risk.Parameters.TradingFeeRate);
            tradingFee = pos.tradingFee(
                fraction,
                oiTotalOnSide,
                oiTotalSharesOnSide,
                price,
                capPayoff,
                tradingFeeRate
            );
            tradingFee = Math.min(tradingFee, value); // if value < tradingFee

            // subtract unwound open interest from the side's aggregate oi value
            // and decrease number of oi shares issued
            // NOTE: use subFloor to avoid reverts with oi rounding issues
            if (pos.isLong) {
                oiLong = oiLong.subFloor(
                    pos.oiCurrent(fraction, oiTotalOnSide, oiTotalSharesOnSide)
                );
                oiLongShares -= pos.oiSharesCurrent(fraction);
            } else {
                oiShort = oiShort.subFloor(
                    pos.oiCurrent(fraction, oiTotalOnSide, oiTotalSharesOnSide)
                );
                oiShortShares -= pos.oiSharesCurrent(fraction);
            }

            // register the amount to be minted/burned
            // capPayoff prevents overflow reverts with int256 cast
            _registerMintOrBurn(int256(value) - int256(cost));

            // store the updated position info data by reducing the
            // oiShares and fraction remaining of initial position
            pos.oiShares -= uint240(pos.oiSharesCurrent(fraction));
            pos.fractionRemaining = pos.updatedFractionRemaining(fraction);
            positions.set(msg.sender, positionId, pos);
        }

        // emit unwind event
        emit Unwind(msg.sender, positionId, fraction, int256(value) - int256(cost), price);

        // mint or burn the pnl for the position
        if (value >= cost) {
            ovl.mint(address(this), value - cost);
        } else {
            ovl.burn(cost - value);
        }

        // transfer out the unwound position value less fees to trader
        ovl.transfer(msg.sender, value - tradingFee);

        // send trading fees to trading fee recipient
        ovl.transfer(IOverlayV1Factory(factory).feeRecipient(), tradingFee);
    }

    /// @dev liquidates a liquidatable position
    function liquidate(address owner, uint256 positionId) external notShutdown {
        uint256 value;
        uint256 cost;
        uint256 price;
        uint256 liquidationFee;
        uint256 marginToBurn;
        uint256 marginRemaining;
        // avoids stack too deep
        {
            // check position exists
            Position.Info memory pos = positions.get(owner, positionId);
            require(pos.exists(), "OVLV1:!position");

            // call to update before any effects
            Oracle.Data memory data = update();

            // cache for gas savings
            uint256 oiTotalOnSide = pos.isLong ? oiLong : oiShort;
            uint256 oiTotalSharesOnSide = pos.isLong ? oiLongShares : oiShortShares;
            uint256 capPayoff = params.get(Risk.Parameters.CapPayoff);

            // entire position should be liquidated
            uint256 fraction = ONE;

            // Use mid price without volume for liquidation (oracle price effectively) to
            // prevent market impact manipulation from causing unneccessary liquidations
            price = _midFromFeed(data);

            // check position is liquidatable
            require(
                pos.liquidatable(
                    oiTotalOnSide,
                    oiTotalSharesOnSide,
                    price,
                    capPayoff,
                    params.get(Risk.Parameters.MaintenanceMarginFraction),
                    params.get(Risk.Parameters.LiquidationFeeRate)
                ),
                "OVLV1:!liquidatable"
            );

            // calculate the value and cost of the position for pnl determinations
            // and amount to transfer
            value = pos.value(fraction, oiTotalOnSide, oiTotalSharesOnSide, price, capPayoff);
            cost = pos.cost(fraction);

            // calculate the liquidation fee as % on remaining value
            // sent as reward to liquidator
            liquidationFee = value.mulDown(params.get(Risk.Parameters.LiquidationFeeRate));
            marginRemaining = value - liquidationFee;

            // Reduce burn amount further by the mm burn rate, as insurance
            // for cases when not liquidated in time
            marginToBurn = marginRemaining.mulDown(
                params.get(Risk.Parameters.MaintenanceMarginBurnRate)
            );
            marginRemaining -= marginToBurn;

            // subtract liquidated open interest from the side's aggregate oi value
            // and decrease number of oi shares issued
            // NOTE: use subFloor to avoid reverts with oi rounding issues
            if (pos.isLong) {
                oiLong = oiLong.subFloor(
                    pos.oiCurrent(fraction, oiTotalOnSide, oiTotalSharesOnSide)
                );
                oiLongShares -= pos.oiSharesCurrent(fraction);
            } else {
                oiShort = oiShort.subFloor(
                    pos.oiCurrent(fraction, oiTotalOnSide, oiTotalSharesOnSide)
                );
                oiShortShares -= pos.oiSharesCurrent(fraction);
            }

            // register the amount to be burned
            _registerMintOrBurn(int256(value) - int256(cost) - int256(marginToBurn));

            // store the updated position info data. mark as liquidated
            pos.liquidated = true;
            pos.oiShares = 0;
            pos.fractionRemaining = 0;
            positions.set(owner, positionId, pos);
        }

        // emit liquidate event
        emit Liquidate(
            msg.sender,
            owner,
            positionId,
            int256(value) - int256(cost) - int256(marginToBurn),
            price
        );

        // burn the pnl for the position + insurance margin
        ovl.burn(cost - value + marginToBurn);

        // transfer out the liquidation fee to liquidator for reward
        ovl.transfer(msg.sender, liquidationFee);

        // send remaining margin to trading fee recipient
        ovl.transfer(IOverlayV1Factory(factory).feeRecipient(), marginRemaining);
    }

    /// @dev updates market: pays funding and fetches freshest data from feed
    /// @dev update is called every time market is interacted with
    function update() public returns (Oracle.Data memory) {
        // pay funding for time elasped since last interaction w market
        _payFunding();

        // fetch new oracle data from feed
        // applies sanity check in case of data manipulation
        Oracle.Data memory data = IOverlayV1Feed(feed).latest();
        require(dataIsValid(data), "OVLV1:!data");

        // return the latest data from feed
        return data;
    }

    /// @dev sanity check on data fetched from oracle in case of manipulation
    /// @dev rough check that log price bounded by +/- priceDriftUpperLimit * dt
    /// @dev when comparing priceMacro(now) vs priceMacro(now - macroWindow)
    function dataIsValid(Oracle.Data memory data) public view returns (bool) {
        // upper and lower limits are e**(+/- priceDriftUpperLimit * dt)
        uint256 _dpUpperLimit = dpUpperLimit;
        uint256 _dpLowerLimit = ONE.divDown(_dpUpperLimit);

        // compare current price over macro window vs price over macro window
        // one macro window in the past
        uint256 priceNow = data.priceOverMacroWindow;
        uint256 priceLast = data.priceOneMacroWindowAgo;
        if (priceLast == 0 || priceNow == 0) {
            // data is not valid if price is zero
            return false;
        }

        // price is valid if within upper and lower limits on drift given
        // time elapsed over one macro window
        uint256 dp = priceNow.divUp(priceLast);
        return (dp >= _dpLowerLimit && dp <= _dpUpperLimit);
    }

    /// @notice Current open interest after funding payments transferred
    /// @notice from overweight oi side to underweight oi side
    /// @dev The value of oiOverweight must be >= oiUnderweight
    function oiAfterFunding(
        uint256 oiOverweight,
        uint256 oiUnderweight,
        uint256 timeElapsed
    ) public view returns (uint256, uint256) {
        uint256 oiTotal = oiOverweight + oiUnderweight;
        uint256 oiImbalance = oiOverweight - oiUnderweight;
        uint256 oiInvariant = oiUnderweight.mulUp(oiOverweight);

        // If no OI or imbalance, no funding occurs. Handles div by zero case below
        if (oiTotal == 0 || oiImbalance == 0) {
            return (oiOverweight, oiUnderweight);
        }

        // draw down the imbalance by factor of e**(-2*k*t)
        // but min to zero if pow = 2*k*t exceeds MAX_NATURAL_EXPONENT
        uint256 fundingFactor;
        uint256 pow = 2 * params.get(Risk.Parameters.K) * timeElapsed;
        if (pow < MAX_NATURAL_EXPONENT) {
            fundingFactor = ONE.divDown(pow.expUp()); // e**(-pow)
        }

        // Decrease total aggregate open interest (i.e. oiLong + oiShort)
        // to compensate protocol for pro-rata share of imbalance liability
        // OI_tot(t) = OI_tot(0) * \
        //  sqrt( 1 - (OI_imb(0)/OI_tot(0))**2 * (1 - e**(-4*k*t)) )

        // Guaranteed 0 <= underRoot <= 1
        uint256 oiImbFraction = oiImbalance.divDown(oiTotal);
        uint256 underRoot = ONE -
            oiImbFraction.mulDown(oiImbFraction).mulDown(
                ONE - fundingFactor.mulDown(fundingFactor)
            );

        // oiTotalNow guaranteed <= oiTotalBefore (burn happens)
        oiTotal = oiTotal.mulDown(underRoot.powDown(ONE / 2));

        // Time decay imbalance: OI_imb(t) = OI_imb(0) * e**(-2*k*t)
        // oiImbalanceNow guaranteed <= oiImbalanceBefore
        oiImbalance = oiImbalance.mulDown(fundingFactor);

        // overweight pays underweight
        // use oiOver * oiUnder = invariant for oiUnderNow to avoid any
        // potential overflow reverts
        oiOverweight = (oiTotal + oiImbalance) / 2;
        if (oiOverweight != 0) {
            oiUnderweight = oiInvariant.divUp(oiOverweight);
        }
        return (oiOverweight, oiUnderweight);
    }

    /// @dev current oi cap with adjustments to lower in the event
    /// @dev market has printed a lot in recent past
    function capOiAdjustedForCircuitBreaker(uint256 cap) public view returns (uint256) {
        // Adjust cap downward for circuit breaker. Use snapshotMinted
        // but transformed to account for decay in magnitude of minted since
        // last snapshot taken
        Roller.Snapshot memory snapshot = snapshotMinted;
        uint256 circuitBreakerWindow = params.get(Risk.Parameters.CircuitBreakerWindow);
        snapshot = snapshot.transform(block.timestamp, circuitBreakerWindow, 0);
        cap = circuitBreaker(snapshot, cap);
        return cap;
    }

    /// @dev bound on oi cap from circuit breaker
    /// @dev Three cases:
    /// @dev 1. minted < 1x target amount over circuitBreakerWindow: return cap
    /// @dev 2. minted > 2x target amount over last circuitBreakerWindow: return 0
    /// @dev 3. minted between 1x and 2x target amount: return cap * (2 - minted/target)
    function circuitBreaker(Roller.Snapshot memory snapshot, uint256 cap)
        public
        view
        returns (uint256)
    {
        int256 minted = int256(snapshot.cumulative());
        uint256 circuitBreakerMintTarget = params.get(Risk.Parameters.CircuitBreakerMintTarget);
        if (minted <= int256(circuitBreakerMintTarget)) {
            return cap;
        } else if (minted >= 2 * int256(circuitBreakerMintTarget)) {
            return 0;
        }

        // case 3 (circuit breaker adjustment downward)
        uint256 adjustment = 2 * ONE - uint256(minted).divDown(circuitBreakerMintTarget);
        return cap.mulDown(adjustment);
    }

    /// @dev current notional cap with adjustments to prevent
    /// @dev front-running trade and back-running trade
    function capNotionalAdjustedForBounds(Oracle.Data memory data, uint256 cap)
        public
        view
        returns (uint256)
    {
        if (data.hasReserve) {
            // Adjust cap downward if exceeds bounds from front run attack
            cap = Math.min(cap, frontRunBound(data));

            // Adjust cap downward if exceeds bounds from back run attack
            cap = Math.min(cap, backRunBound(data));
        }
        return cap;
    }

    /// @dev bound on notional cap to mitigate front-running attack
    /// @dev bound = lmbda * reserveInOvl
    function frontRunBound(Oracle.Data memory data) public view returns (uint256) {
        uint256 lmbda = params.get(Risk.Parameters.Lmbda);
        return lmbda.mulDown(data.reserveOverMicroWindow);
    }

    /// @dev bound on notional cap to mitigate back-running attack
    /// @dev bound = macroWindowInBlocks * reserveInOvl * 2 * delta
    function backRunBound(Oracle.Data memory data) public view returns (uint256) {
        uint256 averageBlockTime = params.get(Risk.Parameters.AverageBlockTime);
        uint256 window = (data.macroWindow * ONE) / averageBlockTime;
        uint256 delta = params.get(Risk.Parameters.Delta);
        return delta.mulDown(data.reserveOverMicroWindow).mulDown(window).mulDown(2 * ONE);
    }

    /// @dev Returns the open interest in number of contracts for a given notional
    /// @dev Uses _midFromFeed(data) price to calculate oi: OI = Q / P
    function oiFromNotional(uint256 notional, uint256 midPrice) public view returns (uint256) {
        return notional.divDown(midPrice);
    }

    /// @dev bid price given oracle data and recent volume
    function bid(Oracle.Data memory data, uint256 volume) public view returns (uint256 bid_) {
        bid_ = Math.min(data.priceOverMicroWindow, data.priceOverMacroWindow);

        // add static spread (delta) and market impact (lmbda * volume)
        uint256 delta = params.get(Risk.Parameters.Delta);
        uint256 lmbda = params.get(Risk.Parameters.Lmbda);
        uint256 pow = delta + lmbda.mulUp(volume);
        require(pow < MAX_NATURAL_EXPONENT, "OVLV1:slippage>max");

        bid_ = bid_.mulDown(ONE.divDown(pow.expUp())); // bid * e**(-pow)
    }

    /// @dev ask price given oracle data and recent volume
    function ask(Oracle.Data memory data, uint256 volume) public view returns (uint256 ask_) {
        ask_ = Math.max(data.priceOverMicroWindow, data.priceOverMacroWindow);

        // add static spread (delta) and market impact (lmbda * volume)
        uint256 delta = params.get(Risk.Parameters.Delta);
        uint256 lmbda = params.get(Risk.Parameters.Lmbda);
        uint256 pow = delta + lmbda.mulUp(volume);
        require(pow < MAX_NATURAL_EXPONENT, "OVLV1:slippage>max");

        ask_ = ask_.mulUp(pow.expUp()); // ask * e**(pow)
    }

    /// @dev mid price without impact/spread given oracle data and recent volume
    /// @dev used for gas savings to avoid accessing storage for delta, lmbda
    function _midFromFeed(Oracle.Data memory data) private view returns (uint256 mid_) {
        mid_ = Math.average(data.priceOverMicroWindow, data.priceOverMacroWindow);
    }

    /// @dev Rolling volume adjustments on bid side to be used for market impact.
    /// @dev Volume values are normalized with respect to cap
    function _registerVolumeBid(
        Oracle.Data memory data,
        uint256 volume,
        uint256 cap
    ) private returns (uint256) {
        // save gas with snapshot in memory
        Roller.Snapshot memory snapshot = snapshotVolumeBid;
        int256 value = int256(volume.divUp(cap));

        // calculates the decay in the rolling volume since last snapshot
        // and determines new window to decay over
        snapshot = snapshot.transform(block.timestamp, data.microWindow, value);

        // store the transformed snapshot
        snapshotVolumeBid = snapshot;

        // return the cumulative volume
        return uint256(snapshot.cumulative());
    }

    /// @dev Rolling volume adjustments on ask side to be used for market impact.
    /// @dev Volume values are normalized with respect to cap
    function _registerVolumeAsk(
        Oracle.Data memory data,
        uint256 volume,
        uint256 cap
    ) private returns (uint256) {
        // save gas with snapshot in memory
        Roller.Snapshot memory snapshot = snapshotVolumeAsk;
        int256 value = int256(volume.divUp(cap));

        // calculates the decay in the rolling volume since last snapshot
        // and determines new window to decay over
        snapshot = snapshot.transform(block.timestamp, data.microWindow, value);

        // store the transformed snapshot
        snapshotVolumeAsk = snapshot;

        // return the cumulative volume
        return uint256(snapshot.cumulative());
    }

    /// @notice Rolling mint accumulator to be used for circuit breaker
    /// @dev value > 0 registers a mint, value <= 0 registers a burn
    function _registerMintOrBurn(int256 value) private returns (int256) {
        // save gas with snapshot in memory
        Roller.Snapshot memory snapshot = snapshotMinted;

        // calculates the decay in the rolling amount minted since last snapshot
        // and determines new window to decay over
        uint256 circuitBreakerWindow = params.get(Risk.Parameters.CircuitBreakerWindow);
        snapshot = snapshot.transform(block.timestamp, circuitBreakerWindow, value);

        // store the transformed snapshot
        snapshotMinted = snapshot;

        // return the cumulative mint amount
        int256 minted = snapshot.cumulative();
        return minted;
    }

    /// @notice Updates the market for funding changes to open interest
    /// @notice since last time market was interacted with
    function _payFunding() private {
        // apply funding if at least one block has passed
        uint256 timeElapsed = block.timestamp - timestampUpdateLast;
        if (timeElapsed > 0) {
            // calculate adjustments to oi due to funding
            bool isLongOverweight = oiLong > oiShort;
            uint256 oiOverweight = isLongOverweight ? oiLong : oiShort;
            uint256 oiUnderweight = isLongOverweight ? oiShort : oiLong;
            (oiOverweight, oiUnderweight) = oiAfterFunding(
                oiOverweight,
                oiUnderweight,
                timeElapsed
            );

            // pay funding
            oiLong = isLongOverweight ? oiOverweight : oiUnderweight;
            oiShort = isLongOverweight ? oiUnderweight : oiOverweight;

            // set last time market was updated
            timestampUpdateLast = block.timestamp;
        }
    }

    /// @notice Adds open interest and open interest shares to aggregate storage
    /// @notice pairs (oiLong, oiLongShares) or (oiShort, oiShortShares)
    /// @return oiShares_ as the new position's shares of aggregate open interest
    function _addToOiAggregates(
        uint256 oi,
        uint256 capOi,
        bool isLong
    ) private returns (uint256 oiShares_) {
        // cache for gas savings
        uint256 oiTotalOnSide = isLong ? oiLong : oiShort;
        uint256 oiTotalSharesOnSide = isLong ? oiLongShares : oiShortShares;

        // calculate oi shares
        uint256 oiShares = Position.calcOiShares(oi, oiTotalOnSide, oiTotalSharesOnSide);

        // add oi and oi shares to temp aggregate values
        oiTotalOnSide += oi;
        oiTotalSharesOnSide += oiShares;

        // check new total oi on side does not exceed capOi after
        // adjusted for circuit breaker
        uint256 capOiCircuited = capOiAdjustedForCircuitBreaker(capOi);
        require(oiTotalOnSide <= capOiCircuited, "OVLV1:oi>cap");

        // update total aggregate oi and oi shares storage vars
        if (isLong) {
            oiLong = oiTotalOnSide;
            oiLongShares = oiTotalSharesOnSide;
        } else {
            oiShort = oiTotalOnSide;
            oiShortShares = oiTotalSharesOnSide;
        }

        // return new position's oi shares
        oiShares_ = oiShares;
    }

    /// @notice Sets the governance per-market risk parameter
    /// @dev updates funding state of market but does not fetch from oracle
    /// @dev to avoid edge cases when dataIsValid is false
    function setRiskParam(Risk.Parameters name, uint256 value) external onlyFactory {
        // pay funding to update state of market since last interaction
        _payFunding();

        // check then set risk param
        _checkRiskParam(name, value);
        _cacheRiskCalc(name, value);
        params.set(name, value);
    }

    /// @notice Checks the governance per-market risk parameter is valid
    function _checkRiskParam(Risk.Parameters name, uint256 value) private {
        // checks delta won't cause position to be immediately
        // liquidatable given current leverage cap (capLeverage),
        // liquidation fee rate (liquidationFeeRate), and
        // maintenance margin fraction (maintenanceMarginFraction)
        if (name == Risk.Parameters.Delta) {
            uint256 _delta = value;
            uint256 capLeverage = params.get(Risk.Parameters.CapLeverage);
            uint256 maintenanceMarginFraction = params.get(
                Risk.Parameters.MaintenanceMarginFraction
            );
            uint256 liquidationFeeRate = params.get(Risk.Parameters.LiquidationFeeRate);
            require(
                capLeverage <=
                    ONE.divDown(
                        2 * _delta + maintenanceMarginFraction.divDown(ONE - liquidationFeeRate)
                    ),
                "OVLV1: max lev immediately liquidatable"
            );
        }

        // checks capLeverage won't cause position to be immediately
        // liquidatable given current spread (delta),
        // liquidation fee rate (liquidationFeeRate), and
        // maintenance margin fraction (maintenanceMarginFraction)
        if (name == Risk.Parameters.CapLeverage) {
            uint256 _capLeverage = value;
            uint256 delta = params.get(Risk.Parameters.Delta);
            uint256 maintenanceMarginFraction = params.get(
                Risk.Parameters.MaintenanceMarginFraction
            );
            uint256 liquidationFeeRate = params.get(Risk.Parameters.LiquidationFeeRate);
            require(
                _capLeverage <=
                    ONE.divDown(
                        2 * delta + maintenanceMarginFraction.divDown(ONE - liquidationFeeRate)
                    ),
                "OVLV1: max lev immediately liquidatable"
            );
        }

        // checks maintenanceMarginFraction won't cause position
        // to be immediately liquidatable given current spread (delta),
        // liquidation fee rate (liquidationFeeRate),
        // and leverage cap (capLeverage)
        if (name == Risk.Parameters.MaintenanceMarginFraction) {
            uint256 _maintenanceMarginFraction = value;
            uint256 delta = params.get(Risk.Parameters.Delta);
            uint256 capLeverage = params.get(Risk.Parameters.CapLeverage);
            uint256 liquidationFeeRate = params.get(Risk.Parameters.LiquidationFeeRate);
            require(
                capLeverage <=
                    ONE.divDown(
                        2 * delta + _maintenanceMarginFraction.divDown(ONE - liquidationFeeRate)
                    ),
                "OVLV1: max lev immediately liquidatable"
            );
        }

        // checks liquidationFeeRate won't cause position
        // to be immediately liquidatable given current spread (delta),
        // leverage cap (capLeverage), and
        // maintenance margin fraction (maintenanceMarginFraction)
        if (name == Risk.Parameters.LiquidationFeeRate) {
            uint256 _liquidationFeeRate = value;
            uint256 delta = params.get(Risk.Parameters.Delta);
            uint256 capLeverage = params.get(Risk.Parameters.CapLeverage);
            uint256 maintenanceMarginFraction = params.get(
                Risk.Parameters.MaintenanceMarginFraction
            );
            require(
                capLeverage <=
                    ONE.divDown(
                        2 * delta + maintenanceMarginFraction.divDown(ONE - _liquidationFeeRate)
                    ),
                "OVLV1: max lev immediately liquidatable"
            );
        }

        // checks priceDriftUpperLimit won't cause pow() call in dataIsValid
        // to exceed max
        if (name == Risk.Parameters.PriceDriftUpperLimit) {
            Oracle.Data memory data = IOverlayV1Feed(feed).latest();
            uint256 _priceDriftUpperLimit = value;
            require(
                _priceDriftUpperLimit * data.macroWindow < MAX_NATURAL_EXPONENT,
                "OVLV1: price drift exceeds max exp"
            );
        }
    }

    /// @notice Caches risk param calculations used in market contract
    /// @notice for gas savings
    function _cacheRiskCalc(Risk.Parameters name, uint256 value) private {
        // caches calculations for dpUpperLimit
        // = e**(priceDriftUpperLimit * data.macroWindow)
        if (name == Risk.Parameters.PriceDriftUpperLimit) {
            Oracle.Data memory data = IOverlayV1Feed(feed).latest();
            uint256 _priceDriftUpperLimit = value;
            uint256 pow = _priceDriftUpperLimit * data.macroWindow;
            dpUpperLimit = pow.expUp(); // e**(pow)
        }
    }

    /// @notice Irreversibly shuts down the market. Can be triggered by
    /// @notice governance through factory contract in the event of an emergency
    function shutdown() external notShutdown onlyFactory {
        isShutdown = true;
    }

    /// @notice Allows emergency withdrawal of remaining collateral
    /// @notice associated with position. Ignores any outstanding PnL and
    /// @notice funding considerations
    function emergencyWithdraw(uint256 positionId) external hasShutdown {
        // check position exists
        Position.Info memory pos = positions.get(msg.sender, positionId);
        require(pos.exists(), "OVLV1:!position");

        // calculate remaining collateral backing position
        uint256 fraction = ONE;
        uint256 cost = pos.cost(fraction);
        cost = Math.min(ovl.balanceOf(address(this)), cost); // if cost > balance

        // set fraction remaining to zero so position no longer exists
        pos.fractionRemaining = 0;
        positions.set(msg.sender, positionId, pos);

        // emit withdraw event
        emit EmergencyWithdraw(msg.sender, positionId, cost);

        // transfer available collateral out to position owner
        ovl.transfer(msg.sender, cost);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oi","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Build","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateral","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"int256","name":"mint","type":"int256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fraction","type":"uint256"},{"indexed":false,"internalType":"int256","name":"mint","type":"int256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Unwind","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"data","type":"tuple"},{"internalType":"uint256","name":"volume","type":"uint256"}],"name":"ask","outputs":[{"internalType":"uint256","name":"ask_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"data","type":"tuple"}],"name":"backRunBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"data","type":"tuple"},{"internalType":"uint256","name":"volume","type":"uint256"}],"name":"bid","outputs":[{"internalType":"uint256","name":"bid_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"priceLimit","type":"uint256"}],"name":"build","outputs":[{"internalType":"uint256","name":"positionId_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"data","type":"tuple"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"capNotionalAdjustedForBounds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"capOiAdjustedForCircuitBreaker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"uint32","name":"window","type":"uint32"},{"internalType":"int192","name":"accumulator","type":"int192"}],"internalType":"struct Roller.Snapshot","name":"snapshot","type":"tuple"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"circuitBreaker","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"data","type":"tuple"}],"name":"dataIsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dpUpperLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"data","type":"tuple"}],"name":"frontRunBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[15]","name":"_params","type":"uint256[15]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"oiOverweight","type":"uint256"},{"internalType":"uint256","name":"oiUnderweight","type":"uint256"},{"internalType":"uint256","name":"timeElapsed","type":"uint256"}],"name":"oiAfterFunding","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"notional","type":"uint256"},{"internalType":"uint256","name":"midPrice","type":"uint256"}],"name":"oiFromNotional","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oiLong","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oiLongShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oiShort","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oiShortShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ovl","outputs":[{"internalType":"contract IOverlayV1Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"params","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"positions","outputs":[{"internalType":"uint96","name":"notionalInitial","type":"uint96"},{"internalType":"uint96","name":"debtInitial","type":"uint96"},{"internalType":"int24","name":"midTick","type":"int24"},{"internalType":"int24","name":"entryTick","type":"int24"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"bool","name":"liquidated","type":"bool"},{"internalType":"uint240","name":"oiShares","type":"uint240"},{"internalType":"uint16","name":"fractionRemaining","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum Risk.Parameters","name":"name","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setRiskParam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"snapshotMinted","outputs":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"uint32","name":"window","type":"uint32"},{"internalType":"int192","name":"accumulator","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"snapshotVolumeAsk","outputs":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"uint32","name":"window","type":"uint32"},{"internalType":"int192","name":"accumulator","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"snapshotVolumeBid","outputs":[{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"uint32","name":"window","type":"uint32"},{"internalType":"int192","name":"accumulator","type":"int192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timestampUpdateLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"uint256","name":"fraction","type":"uint256"},{"internalType":"uint256","name":"priceLimit","type":"uint256"}],"name":"unwind","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"update","outputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"microWindow","type":"uint256"},{"internalType":"uint256","name":"macroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMicroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOverMacroWindow","type":"uint256"},{"internalType":"uint256","name":"priceOneMacroWindowAgo","type":"uint256"},{"internalType":"uint256","name":"reserveOverMicroWindow","type":"uint256"},{"internalType":"bool","name":"hasReserve","type":"bool"}],"internalType":"struct Oracle.Data","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b506000806000336001600160a01b031663890357306040518163ffffffff1660e01b8152600401606060405180830381865afa15801562000056573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200007c9190620000bb565b6001600160a01b0392831660805290821660a0521660c0525062000105915050565b80516001600160a01b0381168114620000b657600080fd5b919050565b600080600060608486031215620000d157600080fd5b620000dc846200009e565b9250620000ec602085016200009e565b9150620000fc604085016200009e565b90509250925092565b60805160a05160c051614db5620001c8600039600081816105b001528181610d00015281816115260152818161162f015281816118520152818161209a01526122ec0152600081816102460152818161167001528181611bcd01528181612e8501526131fd01526000818161052e01528181610b0801528181610ba501528181610c2f01528181610cd101528181610eae01528181610f8c0152818161144b015281816114f701528181611f4d01528181611ff1015261206b0152614db56000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80638eba35351161011a578063bf65b2fb116100ad578063d43cbd8e1161007c578063d43cbd8e146105db578063d565cc33146105ee578063ecc1619114610616578063f333fe1314610629578063fc0e74d11461063257600080fd5b8063bf65b2fb1461058b578063bf86d6901461059e578063c45a0155146105ab578063c6838e8b146105d257600080fd5b8063a2e62045116100e9578063a2e62045146104be578063b29fa9c314610529578063b445e2e714610550578063bcbaf4871461057857600080fd5b80638eba35351461045d57806392aac701146104705780639d2f053c146104835780639f0a54591461049657600080fd5b806358171a61116101925780635dedde6d116101615780635dedde6d1461041b578063640d0c28146104245780636c629159146104375780638607f5c31461044a57600080fd5b806358171a611461038457806359968288146103a75780635ad7226f146103ba5780635b6df29a146103cd57600080fd5b806337a7b7d8116101ce57806337a7b7d81461024157806346322c3714610280578063514ea4bf146102955780635312ea8e1461037157600080fd5b806309163014146102005780632acb38101461021c5780632eda95c2146102255780633197e19214610238575b600080fd5b61020960105481565b6040519081526020015b60405180910390f35b61020960115481565b6102096102333660046146a3565b61063a565b61020960195481565b6102687f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610213565b61029361028e3660046146d0565b6106d4565b005b6103136102a33660046146fc565b601660205260009081526040902080546001909101546001600160601b0380831692600160601b810490911691600160c01b8204600290810b92600160d81b810490910b91600160f01b80830460ff90811693600160f81b900416916001600160f01b03811691900461ffff1688565b604080516001600160601b03998a168152989097166020890152600295860b968801969096529290930b60608601521515608085015290151560a08401526001600160f01b031660c083015261ffff1660e082015261010001610213565b61029361037f3660046146fc565b610dfb565b610397610392366004614715565b611008565b6040519015158152602001610213565b6102096103b5366004614732565b611074565b6102936103c8366004614771565b611624565b6015546103f59063ffffffff80821691600160201b810490911690600160401b900460170b83565b6040805163ffffffff948516815293909216602084015260170b90820152606001610213565b610209600f5481565b6102936104323660046147f0565b611847565b610209610445366004614715565b6118bb565b6102096104583660046146a3565b6118e9565b61020961046b366004614820565b611973565b61020961047e366004614715565b611988565b6102096104913660046146fc565b611a0e565b6104a96104a43660046146d0565b611a25565b60408051928352602083019190915201610213565b6104c6611b77565b6040516102139190600061010082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e0830151151560e083015292915050565b6102687f000000000000000000000000000000000000000000000000000000000000000081565b6013546103f59063ffffffff80821691600160201b810490911690600160401b900460170b83565b610293610586366004614857565b611c98565b6102096105993660046146fc565b612196565b601a546103979060ff1681565b6102687f000000000000000000000000000000000000000000000000000000000000000081565b61020960185481565b6102096105e9366004614889565b612204565b6014546103f59063ffffffff80821691600160201b810490911690600160401b900460170b83565b6102096106243660046146a3565b612288565b61020960125481565b6102936122be565b600061064e83606001518460800151612338565b9050600061065d81600261234f565b9050600061066c81600161234f565b9050600061067a828661237d565b610684908461492b565b90506801158e460913d0000081106106b75760405162461bcd60e51b81526004016106ae90614943565b60405180910390fd5b6106ca6106c3826123cc565b859061237d565b9695505050505050565b601a5460ff16156106f75760405162461bcd60e51b81526004016106ae9061496f565b670de0b6b3a76400008211156107445760405162461bcd60e51b815260206004820152601260248201527109eac98ac6274cce4c2c6e8d2dedc7cdac2f60731b60448201526064016106ae565b61075961075083612467565b61ffff166124e0565b9150600082116107a05760405162461bcd60e51b815260206004820152601260248201527127ab262b189d333930b1ba34b7b71e36b4b760711b60448201526064016106ae565b60008060008060006107b0611b77565b905060006107c06016338b612507565b90506107cb81612620565b6107e75760405162461bcd60e51b81526004016106ae90614998565b600081608001516107fa576010546107fe565b600f545b90506000826080015161081357601254610817565b6011545b905061085782826108278761263d565b6108336000600361234f565b61083f6000600861234f565b61084b6000600a61234f565b89959493929190612651565b156108995760405162461bcd60e51b81526020600482015260126024820152714f564c56313a6c6971756964617461626c6560701b60448201526064016106ae565b60006108b66108ad8661062484600461234f565b61046b8761263d565b905083608001516108eb576108e685610233876108e08f88888b6126da909392919063ffffffff16565b85612717565b610910565b610910856104588761090a8f88888b6126da909392919063ffffffff16565b856127de565b965083608001516109245789871115610929565b898710155b6109455760405162461bcd60e51b81526004016106ae90614943565b600061095281600361234f565b9050610962858d86868c866128a0565b995061096e858d6129ac565b9850600061097d81600b61234f565b905061098e868e87878d87876129d4565b975061099a888c6129fe565b97508560800151156109e7576109be6109b5878f88886126da565b600f5490612a0d565b600f556109cb868e612a28565b601160008282546109dc91906149c1565b90915550610a239050565b6109ff6109f6878f88886126da565b60105490612a0d565b601055610a0c868e612a28565b60126000828254610a1d91906149c1565b90915550505b610a35610a308b8d6149d8565b612a4b565b50610a40868e612a28565b8660c001818151610a519190614a17565b6001600160f01b0316905250610a67868e612b09565b8660e0019061ffff16908161ffff1681525050610a92338f886016612b83909392919063ffffffff16565b50505050505050336001600160a01b03167fc13b78a0772a556b5387d497953273371ed42cff2af20c019d9f119a737685ba88888688610ad291906149d8565b604080519384526020840192909252908201526060810185905260800160405180910390a2828410610b9b576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166340c10f1930610b3886886149c1565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610b7e57600080fd5b505af1158015610b92573d6000803e3d6000fd5b50505050610c25565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166342966c68610bd486866149c1565b6040518263ffffffff1660e01b8152600401610bf291815260200190565b600060405180830381600087803b158015610c0c57600080fd5b505af1158015610c20573d6000803e3d6000fd5b505050505b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663a9059cbb33610c5f84886149c1565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610caa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cce9190614a3f565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d809190614a5c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df19190614a3f565b5050505050505050565b601a5460ff16610e405760405162461bcd60e51b815260206004820152601060248201526f27ab262b189d1010b9b43aba3237bbb760811b60448201526064016106ae565b6000610e4e60163384612507565b9050610e5981612620565b610e755760405162461bcd60e51b81526004016106ae90614998565b670de0b6b3a76400006000610e8a83836129ac565b6040516370a0823160e01b8152306004820152909150610f1f906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f199190614a79565b826129fe565b600060e08501529050610f356016338686612b83565b604080518581526020810183905233917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595910160405180910390a260405163a9059cbb60e01b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110019190614a3f565b5050505050565b60195460009081611021670de0b6b3a764000083612ca8565b608085015160a08601519192509080158061103a575081155b1561104b5750600095945050505050565b60006110578383612cd7565b90508381101580156110695750848111155b979650505050505050565b601a5460009060ff161561109a5760405162461bcd60e51b81526004016106ae9061496f565b670de0b6b3a76400008410156110e25760405162461bcd60e51b815260206004820152600d60248201526c27ab262b189d3632bb1e36b4b760991b60448201526064016106ae565b6110ee6000600561234f565b84111561112d5760405162461bcd60e51b815260206004820152600d60248201526c09eac98ac6274d8caec7cdac2f609b1b60448201526064016106ae565b6111396000600c61234f565b85101561117f5760405162461bcd60e51b815260206004820152601460248201527327ab262b189d31b7b63630ba32b930b61e36b4b760611b60448201526064016106ae565b600080600080600061118f611b77565b9050600061119d8b8b61237d565b905060006111aa8361263d565b90506111b68282611973565b9650600087116111f65760405162461bcd60e51b815260206004820152600b60248201526a04f564c56313a6f693d3d360ac1b60448201526064016106ae565b6112008c836149c1565b95506112186112116000600b61234f565b839061237d565b9350600061123461122e8561062484600461234f565b83611973565b90508a61124f5761124a84610458868b856127de565b61125e565b61125e84610233868b85612717565b95508a61126e5789861015611273565b898611155b61128f5760405162461bcd60e51b81526004016106ae90614943565b600061129c89838e612d08565b90506000604051806101000160405280866001600160601b031681526020018a6001600160601b031681526020016112d386612dd1565b60020b81526020016112e48a612dd1565b60020b81528e15156020820152600060408201526001600160f01b038416606082015260800161131b670de0b6b3a7640000612467565b61ffff16905290506113798d61133357601054611337565b600f545b8e61134457601254611348565b6011545b866113556000600361234f565b6113616000600861234f565b61136d6000600a61234f565b87959493929190612651565b156113bb5760405162461bcd60e51b81526020600482015260126024820152714f564c56313a6c6971756964617461626c6560701b60448201526064016106ae565b6017549a506113cd6016338d84612b83565b601780549060006113dd83614a92565b9091555050604080518c8152602081018c90529081018a90528d15156060820152608081018990523396507fb98b46cc473761b09478db481c36070133bf6b7a18241892f5477e725b063b5a955060a001935061143992505050565b60405180910390a26001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd333061147c858e61492b565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af11580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614a3f565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a69190614a5c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156115f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116179190614a3f565b5050505050949350505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461166c5760405162461bcd60e51b81526004016106ae90614aad565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa1580156116cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f19190614ad6565b905060006116fe8261263d565b116117395760405162461bcd60e51b815260206004820152600b60248201526a4f564c56313a216461746160a81b60448201526064016106ae565b4260185560a0820151604083015161010084015161014085015161179661177261176b83670de0b6b3a76400006149c1565b8490612ca8565b61177d856002614b9c565b611787919061492b565b670de0b6b3a764000090612ca8565b8411156117b55760405162461bcd60e51b81526004016106ae90614bbb565b6101a086015160408601516801158e460913d00000906117d59083614b9c565b106117f25760405162461bcd60e51b81526004016106ae90614c02565b6117fd600d82612e67565b60005b600f811015610df1578781600f811061181b5761181b614b86565b6020020151600082600f811061183357611833614b86565b01558061183f81614a92565b915050611800565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461188f5760405162461bcd60e51b81526004016106ae90614aad565b611897612f32565b6118a18282612fb6565b6118ab8282612e67565b6118b7600083836132c0565b5050565b6000806118c981600161234f565b90506118e28360c00151826132eb90919063ffffffff16565b9392505050565b60006118fd836060015184608001516129fe565b9050600061190c81600261234f565b9050600061191b81600161234f565b90506000611929828661237d565b611933908461492b565b90506801158e460913d00000811061195d5760405162461bcd60e51b81526004016106ae90614943565b6106ca61196c611787836123cc565b85906132eb565b600061197f8383612ca8565b90505b92915050565b60008061199681600e61234f565b9050600081670de0b6b3a764000085604001516119b39190614b9c565b6119bd9190614c5a565b905060006119cc81600261234f565b9050611a056119e4670de0b6b3a76400006002614b9c565b6119ff846119ff8960c00151866132eb90919063ffffffff16565b906132eb565b95945050505050565b600081600f8110611a1e57600080fd5b0154905081565b60008080611a33858761492b565b90506000611a4186886149c1565b90506000611a4f878961237d565b9050821580611a5c575081155b15611a6f57878794509450505050611b6f565b60008087611a7d828061234f565b611a88906002614b9c565b611a929190614b9c565b90506801158e460913d00000811015611ab457611ab1611787826123cc565b91505b6000611ac08587612ca8565b90506000611aed611ad185806132eb565b611ae390670de0b6b3a76400006149c1565b6119ff84806132eb565b611aff90670de0b6b3a76400006149c1565b9050611b28611b21611b1a6002670de0b6b3a7640000614c5a565b839061330c565b88906132eb565b9650611b3486856132eb565b95506002611b42878961492b565b611b4c9190614c5a565b9b508b15611b6157611b5e858d612cd7565b9a505b8b8b98509850505050505050505b935093915050565b611bc1604051806101000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b611bc9612f32565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa158015611c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4e9190614ad6565b9050611c5981611008565b611c935760405162461bcd60e51b815260206004820152600b60248201526a4f564c56313a216461746160a81b60448201526064016106ae565b919050565b601a5460ff1615611cbb5760405162461bcd60e51b81526004016106ae9061496f565b6000808080808080611ccf60168a8a612507565b9050611cda81612620565b611cf65760405162461bcd60e51b81526004016106ae90614998565b6000611d00611b77565b905060008260800151611d1557601054611d19565b600f545b905060008360800151611d2e57601254611d32565b6011545b90506000611d4181600361234f565b9050670de0b6b3a7640000611d558561263d565b9950611d8284848c85611d6a6000600861234f565b611d766000600a61234f565b8c959493929190612651565b611dc45760405162461bcd60e51b81526020600482015260136024820152724f564c56313a216c6971756964617461626c6560681b60448201526064016106ae565b611dd2868286868e876128a0565b9b50611dde86826129ac565b9a50611df6611def6000600a61234f565b8d906132eb565b9850611e02898d6149c1565b9650611e13611b216000600961234f565b9750611e1f88886149c1565b9650856080015115611e6357611e3a6109b5878387876126da565b600f55611e478682612a28565b60116000828254611e5891906149c1565b90915550611e969050565b611e726109f6878387876126da565b601055611e7f8682612a28565b60126000828254611e9091906149c1565b90915550505b611eae88611ea48d8f6149d8565b610a3091906149d8565b50600160a0870152600060c0870181905260e0870152611ed160168f8f89612b83565b505050505050876001600160a01b0316336001600160a01b03167ff1deb4d6391f20e8cad919356063127cf8453da1fdf246eb1b5e4549e848112e8985898b611f1a91906149d8565b611f2491906149d8565b604080519283526020830191909152810188905260600160405180910390a36001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166342966c6883611f7d89896149c1565b611f87919061492b565b6040518263ffffffff1660e01b8152600401611fa591815260200190565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b505060405163a9059cbb60e01b8152336004820152602481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316925063a9059cbb91506044016020604051808303816000875af1158015612044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120689190614a3f565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211a9190614a5c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015612167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218b9190614a3f565b505050505050505050565b6040805160608101825260155463ffffffff8082168352600160201b820481166020840152600160401b90910460170b9282019290925260009182906121e190829060069061234f16565b90506121f082428360006133fe565b91506121fc8285612204565b949350505050565b600080612215846040015160170b90565b9050600061222481600761234f565b9050808213612237578392505050611982565b612242816002614c6e565b821261225357600092505050611982565b600061225f8383612ca8565b612272670de0b6b3a76400006002614b9c565b61227c91906149c1565b90506106ca85826132eb565b60008260e00151156122b8576122a6826122a1856118bb565b6129fe565b91506122b5826122a185611988565b91505b50919050565b601a5460ff16156122e15760405162461bcd60e51b81526004016106ae9061496f565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146123295760405162461bcd60e51b81526004016106ae90614aad565b601a805460ff19166001179055565b600081831015612348578161197f565b5090919050565b60008282600e81111561236457612364614b70565b600f811061237457612374614b86565b01549392505050565b60008061238a8385614b9c565b90508061239b576000915050611982565b670de0b6b3a76400006123af6001836149c1565b6123b99190614c5a565b6123c490600161492b565b915050611982565b6000816123e25750670de0b6b3a7640000919050565b600160ff1b82106124355760405162461bcd60e51b815260206004820152601b60248201527f4669786564506f696e743a2078206f7574206f6620626f756e6473000000000060448201526064016106ae565b816000612441826135fa565b9050600061245b6124548361271061237d565b60016139dc565b9050611a0582826139dc565b60008061247e612710670de0b6b3a7640000614c5a565b9050600061248c8285614c5a565b905061ffff8111156118e25760405162461bcd60e51b815260206004820152601e60248201527f4f564c56313a20466978656443617374206f7574206f6620626f756e6473000060448201526064016106ae565b6000806124f7612710670de0b6b3a7640000614c5a565b90506118e28161ffff8516614b9c565b60408051610100810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e090930182905283519590921b6bffffffffffffffffffffffff1916858301526034808601949094528251808603909401845260548501808452845194830194909420815294905292839020610154830190935282546001600160601b038082168352600160601b8204166074840152600160c01b8104600290810b6094850152600160d81b8204900b60b4840152600160f01b80820460ff908116151560d4860152600160f81b909204909116151560f48401526001909301546001600160f01b0381166101148401529290920461ffff166101349091015290565b60008160a0015115801561198257505060e0015161ffff16151590565b6000611982826060015183608001516139e9565b6000670de0b6b3a7640000816126678a83613a04565b90508960a001518061267f575060e08a015161ffff16155b1561268f57600092505050611069565b600061269f8b848c8c8c8c6128a0565b905060006126ad838861237d565b905060006126bb83886132eb565b90506126c7818361492b565b9092109c9b505050505050505050505050565b6000806126e78686612a28565b90508015806126f4575083155b806126fd575082155b1561270c5760009150506121fc565b6106ca818585613a35565b6040805160608101825260145463ffffffff8082168352600160201b820481166020840152600160401b90910460170b9282019290925260009182906127619086908690612cd716565b60208701519091506127779083904290846133fe565b8051601480546020840151604085015163ffffffff94851667ffffffffffffffff1990931692909217600160201b94909116939093029290921767ffffffffffffffff16600160401b6001600160c01b0384160217905590925060170b9695505050505050565b6040805160608101825260135463ffffffff8082168352600160201b820481166020840152600160401b90910460170b9282019290925260009182906128289086908690612cd716565b602087015190915061283e9083904290846133fe565b8051601380546020840151604085015163ffffffff94851667ffffffffffffffff1990931692909217600160201b94909116939093029290921767ffffffffffffffff16600160401b6001600160c01b0384160217905590925060170b6106ca565b6000806128ad8888613ae8565b905060006128bb8989613a04565b905060006128c98a8a613b05565b905060006128d98b8b8b8b6126da565b905060006128e68c613b2d565b90508b6080015115612969576129246128ff838a61237d565b6122a16129148a670de0b6b3a764000061492b565b61291e868661237d565b9061237d565b61293886612932878661237d565b90612cd7565b612942919061492b565b9550612962612951838361237d565b61295b908561492b565b8790612a0d565b955061299d565b612973828261237d565b61298186612932878661237d565b61298b919061492b565b955061299a612951838a61237d565b95505b50505050509695505050505050565b6000806129b98484613a04565b905060006129c78585613b05565b9050816106ca8183612a0d565b6000806129e5898989898989613b3c565b90506129f1818461237d565b9998505050505050505050565b6000818310612348578161197f565b600080828411612a1e5760006121fc565b6121fc83856149c1565b600080612a3f8460c001516001600160f01b031690565b90506121fc81846132eb565b6040805160608101825260155463ffffffff8082168352600160201b820481166020840152600160401b90910460170b928201929092526000918290612a9690829060069061234f16565b9050612aa4824283876133fe565b8051601580546020840151604085015163ffffffff94851667ffffffffffffffff1990931692909217600160201b94909116939093029290921767ffffffffffffffff16600160401b6001600160c01b0384160217905590925060009060170b611a05565b6000670de0b6b3a7640000821115612b585760405162461bcd60e51b815260206004820152601260248201527109eac98ac6274cce4c2c6e8d2dedc7cdac2f60731b60448201526064016106ae565b6000612b78612b6f84670de0b6b3a76400006149c1565b6119ff86613b67565b90506121fc81612467565b6040516bffffffffffffffffffffffff19606085901b166020820152603481018390528190859060009060540160408051808303601f1901815291815281516020928301208352828201939093529082016000208351815492850151938501516060860151608087015160a08801516001600160601b039485166001600160c01b031990971696909617600160601b94909716939093029590951765ffffffffffff60c01b1916600160c01b62ffffff9283160262ffffff60d81b191617600160d81b9190951602939093176001600160f01b03908116600160f01b94151585026001600160f81b031617600160f81b9315159390930292909217815560c084015160e0909401519390911661ffff9093169091029190911760019091015550505050565b600082612cb757506000611982565b6000612ccb670de0b6b3a764000085614b9c565b90506123c48382614c5a565b600082612ce657506000611982565b6000612cfa670de0b6b3a764000085614b9c565b9050826123af6001836149c1565b60008082612d1857601054612d1c565b600f545b9050600083612d2d57601254612d31565b6011545b90506000612d40878484613b7a565b9050612d4c878461492b565b9250612d58818361492b565b91506000612d6587612196565b905080841115612da65760405162461bcd60e51b815260206004820152600c60248201526b04f564c56313a6f693e6361760a41b60448201526064016106ae565b8515612dbb57600f8490556011839055612dc6565b601084905560128390555b509695505050505050565b600080612de683670de111a6b7de4000613ba3565b90506956d225004ee68c3fffff198112158015612e0d575069fe1c215e8f838e0000008113155b612e555760405162461bcd60e51b81526020600482015260196024820152784f564c56313a207469636b206f7574206f6620626f756e647360381b60448201526064016106ae565b6118e2670de0b6b3a764000082614cf3565b600d82600e811115612e7b57612e7b614b70565b14156118b75760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa158015612ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f069190614ad6565b60408101519091508290600090612f1d9083614b9c565b9050612f28816123cc565b6019555050505050565b600060185442612f4291906149c1565b90508015612fb357601054600f5411600081612f6057601054612f64565b600f545b9050600082612f7557600f54612f79565b6010545b9050612f86828286611a25565b909250905082612f965780612f98565b815b600f5582612fa65781612fa8565b805b601055505042601855505b50565b600282600e811115612fca57612fca614b70565b141561304557806000612fde81600561234f565b90506000612fed81600861234f565b90506000612ffc81600a61234f565b905061302161301661176b83670de0b6b3a76400006149c1565b61177d866002614b9c565b8311156130405760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600582600e81111561305957613059614b70565b14156130c95780600061306d81600261234f565b9050600061307c81600861234f565b9050600061308b81600a61234f565b90506130a561177261176b83670de0b6b3a76400006149c1565b8411156130c45760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600882600e8111156130dd576130dd614b70565b1415613154578060006130f181600261234f565b9050600061310081600561234f565b9050600061310f81600a61234f565b905061313061177261312983670de0b6b3a76400006149c1565b8690612ca8565b82111561314f5760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600a82600e81111561316857613168614b70565b14156131df5780600061317c81600261234f565b9050600061318b81600561234f565b9050600061319a81600861234f565b90506131bb6117726131b486670de0b6b3a76400006149c1565b8390612ca8565b8211156131da5760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600d82600e8111156131f3576131f3614b70565b14156118b75760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa15801561325a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327e9190614ad6565b604081015190915082906801158e460913d000009061329d9083614b9c565b106132ba5760405162461bcd60e51b81526004016106ae90614c02565b50505050565b808383600e8111156132d4576132d4614b70565b600f81106132e4576132e4614b86565b0155505050565b6000806132f88385614b9c565b90506121fc670de0b6b3a764000082614c5a565b60008115806133225750670de0b6b3a764000083145b156133365750670de0b6b3a7640000611982565b8261334357506000611982565b670de0b6b3a764000082141561335a575081611982565b61336d670de0b6b3a76400006002614b9c565b8214156133855761337e83846132eb565b9050611982565b613398670de0b6b3a76400006004614b9c565b8214156133b75760006133ab84856132eb565b90506123c481826132eb565b60006133c38484613cb2565b905060006133d66124548361271061237d565b9050808210156133eb57600092505050611982565b6133f58282613db3565b92505050611982565b6040805160608101825260008082526020820181905291810182905285519091859163ffffffff908116908316101561345b57865163ffffffff9081169061344c908416600160201b61492b565b61345691906149c1565b61346e565b86516134679083614d21565b63ffffffff165b602088015190915063ffffffff16600061348c896040015160170b90565b9050818310158061349b575081155b156134e55760405180606001604052808563ffffffff1681526020016134c089613dc0565b63ffffffff1681526020016134d488613dd9565b60170b8152509450505050506121fc565b816134f084826149c1565b6134fa9083614c6e565b6135049190614cf3565b905060006135128783614d3e565b9050806135565760405180606001604052808663ffffffff1681526020016135398a613dc0565b63ffffffff168152600060209091015295506121fc945050505050565b600061356183613e1c565b9050600061356e89613e1c565b9050600061357c828461492b565b6135868c84614b9c565b61359089896149c1565b61359a9086614b9c565b6135a4919061492b565b6135ae9190614c5a565b905060405180606001604052808963ffffffff1681526020016135d083613dc0565b63ffffffff1681526020016135e486613dd9565b60170b90529d9c50505050505050505050505050565b6000613629680238fd42c5cf03ffff198312158015613622575068070c1cc73b00c800008313155b6009613e33565b60008212156136615761363e826000036135fa565b6a0c097ce7bc90715b34b9f160241b8161365a5761365a614c44565b0592915050565b60006806f05b59d3b200000083126136a157506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec6302628270000000006136d7565b6803782dace9d900000083126136d357506803782dace9d8ffffff19909101906b1425982cf597cd205cef73806136d7565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac6200000084126137275768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613763576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b18800000841261379d57682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126137d7576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac6200000841261381057680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d6310000084126138495768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613882576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c4000084126138bb5768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b6000806121fc838561492b565b60006139f86002848418614c5a565b61197f9084841661492b565b600080613a1084613b67565b90506000613a298261291e87516001600160601b031690565b9050611a05818561237d565b600080806000198587098587029250828110838203039150508060001415613a6f5760008411613a6457600080fd5b5082900490506118e2565b808411613a7b57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b600080613af484613b67565b90506000613a298261291e87613e41565b600080613b1184613b67565b90506000613a298261291e87602001516001600160601b031690565b60006119828260600151613e6e565b600080613b4d8888888888886128a0565b90506000613b5b8989613b05565b90506129f1818361492b565b60006119828260e0015161ffff166124e0565b6000821580613b87575081155b613b9b57613b96848385613a35565b6121fc565b509192915050565b60008083118015613bb75750600160ff1b83105b613c035760405162461bcd60e51b815260206004820152601b60248201527f4669786564506f696e743a2061206f7574206f6620626f756e6473000000000060448201526064016106ae565b600082118015613c165750600160ff1b82105b613c625760405162461bcd60e51b815260206004820152601b60248201527f4669786564506f696e743a2062206f7574206f6620626f756e6473000000000060448201526064016106ae565b82826000613c708383613f33565b9050600080821215613c855781600003613c87565b815b90506000613c9a6124548361271061237d565b9050613ca681846149d8565b98975050505050505050565b600081613cc85750670de0b6b3a7640000611982565b82613cd557506000611982565b613ce6600160ff1b84106006613e33565b82613d0c770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007613e33565b826000670c7d713b49da000083138015613d2d5750670f43fc2c04ee000083125b15613d64576000613d3d84613fed565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050613d72565b81613d6e8461410c565b0290505b670de0b6b3a76400009005613daa680238fd42c5cf03ffff198212801590613da3575068070c1cc73b00c800008213155b6008613e33565b6106ca816135fa565b6000806121fc83856149c1565b60008063ffffffff8311156123485763ffffffff6118e2565b6000806001600160bf1b03198312613e0c576001600160bf1b038313613dff57826118e2565b6001600160bf1b036118e2565b6001600160bf1b03199392505050565b600080821215613e2f5781600003611982565b5090565b816118b7576118b7816144b6565b600080613e5583516001600160601b031690565b90506000613e6284614509565b90506121fc8282612ca8565b600080613e87670de0b6b3a7640000600285900b614c6e565b90506956d225004ee68c3fffff198112158015613eae575069fe1c215e8f838e0000008113155b613ef65760405162461bcd60e51b81526020600482015260196024820152784f564c56313a207469636b206f7574206f6620626f756e647360381b60448201526064016106ae565b6000613f0182613e1c565b90506000821215613f2157613b96611787670de111a6b7de400083614518565b6121fc670de111a6b7de40008261330c565b600080670c7d713b49da000083138015613f545750670f43fc2c04ee000083125b15613f6957613f6283613fed565b9050613f7f565b670de0b6b3a7640000613f7b8461410c565b0290505b6000670c7d713b49da000085138015613f9f5750670f43fc2c04ee000085125b15613fb457613fad85613fed565b9050613fca565b670de0b6b3a7640000613fc68661410c565b0290505b81670de0b6b3a7640000820281613fe357613fe3614c44565b0595945050505050565b670de0b6b3a7640000026000806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff198501028161402e5761402e614c44565b05905060006a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f82050160020295945050505050565b6000670de0b6b3a764000082121561414d57614144826a0c097ce7bc90715b34b9f160241b8161413e5761413e614c44565b0561410c565b60000392915050565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261419e57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126141d6576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261421e576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a7008312614259576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261429057693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126142c757690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126142fc5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261432757680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261435c576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312614391576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126143c5576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac83126143f9576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161442257614422614c44565b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006119828260400151613e6e565b600081158061452e5750670de0b6b3a764000083145b156145425750670de0b6b3a7640000611982565b8261454f57506000611982565b670de0b6b3a7640000821415614566575081611982565b614579670de0b6b3a76400006002614b9c565b82141561458a5761337e838461237d565b61459d670de0b6b3a76400006004614b9c565b8214156145bc5760006145b0848561237d565b90506123c4818261237d565b60006145c88484613cb2565b905060006145db6124548361271061237d565b90506133f582826139dc565b634e487b7160e01b600052604160045260246000fd5b8015158114612fb357600080fd5b600061010080838503121561461f57600080fd5b6040519081019067ffffffffffffffff82118183101715614642576146426145e7565b81604052809250833581526020840135602082015260408401356040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e08401359150614699826145fd565b60e0015292915050565b60008061012083850312156146b757600080fd5b6146c1848461460b565b94610100939093013593505050565b6000806000606084860312156146e557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561470e57600080fd5b5035919050565b6000610100828403121561472857600080fd5b61197f838361460b565b6000806000806080858703121561474857600080fd5b84359350602085013592506040850135614761816145fd565b9396929550929360600135925050565b60006101e080838503121561478557600080fd5b83601f84011261479457600080fd5b60405181810181811067ffffffffffffffff821117156147b6576147b66145e7565b6040529083019080858311156147cb57600080fd5b845b838110156147e55780358252602091820191016147cd565b509095945050505050565b6000806040838503121561480357600080fd5b8235600f811061481257600080fd5b946020939093013593505050565b6000806040838503121561483357600080fd5b50508035926020909101359150565b6001600160a01b0381168114612fb357600080fd5b6000806040838503121561486a57600080fd5b823561481281614842565b803563ffffffff81168114611c9357600080fd5b600080828403608081121561489d57600080fd5b60608112156148ab57600080fd5b506040516060810181811067ffffffffffffffff821117156148cf576148cf6145e7565b6040526148db84614875565b81526148e960208501614875565b602082015260408401358060170b811461490257600080fd5b6040820152946060939093013593505050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561493e5761493e614915565b500190565b60208082526012908201527109eac98ac6274e6d8d2e0e0c2ceca7cdac2f60731b604082015260600190565b6020808252600f908201526e27ab262b189d1039b43aba3237bbb760891b604082015260600190565b6020808252600f908201526e27ab262b189d10b837b9b4ba34b7b760891b604082015260600190565b6000828210156149d3576149d3614915565b500390565b60008083128015600160ff1b8501841216156149f6576149f6614915565b6001600160ff1b0384018313811615614a1157614a11614915565b50500390565b60006001600160f01b0383811690831681811015614a3757614a37614915565b039392505050565b600060208284031215614a5157600080fd5b81516118e2816145fd565b600060208284031215614a6e57600080fd5b81516118e281614842565b600060208284031215614a8b57600080fd5b5051919050565b6000600019821415614aa657614aa6614915565b5060010190565b6020808252600f908201526e4f564c56313a2021666163746f727960881b604082015260600190565b6000610100808385031215614aea57600080fd5b6040519081019067ffffffffffffffff82118183101715614b0d57614b0d6145e7565b81604052835181526020840151602082015260408401516040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c082015260e08401519150614b61826145fd565b60e08101919091529392505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000816000190483118215151615614bb657614bb6614915565b500290565b60208082526027908201527f4f564c56313a206d6178206c657620696d6d6564696174656c79206c6971756960408201526664617461626c6560c81b606082015260800190565b60208082526022908201527f4f564c56313a2070726963652064726966742065786365656473206d61782065604082015261078760f41b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b600082614c6957614c69614c44565b500490565b60006001600160ff1b0381841382841380821686840486111615614c9457614c94614915565b600160ff1b6000871282811687830589121615614cb357614cb3614915565b60008712925087820587128484161615614ccf57614ccf614915565b87850587128184161615614ce557614ce5614915565b505050929093029392505050565b600082614d0257614d02614c44565b600160ff1b821460001984141615614d1c57614d1c614915565b500590565b600063ffffffff83811690831681811015614a3757614a37614915565b600080821280156001600160ff1b0384900385131615614d6057614d60614915565b600160ff1b8390038412811615614d7957614d79614915565b5050019056fea2646970667358221220ee478acafbb18cfc986294a7b7b8431a058e742dfd924976abd552d038da8a6264736f6c634300080a0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c80638eba35351161011a578063bf65b2fb116100ad578063d43cbd8e1161007c578063d43cbd8e146105db578063d565cc33146105ee578063ecc1619114610616578063f333fe1314610629578063fc0e74d11461063257600080fd5b8063bf65b2fb1461058b578063bf86d6901461059e578063c45a0155146105ab578063c6838e8b146105d257600080fd5b8063a2e62045116100e9578063a2e62045146104be578063b29fa9c314610529578063b445e2e714610550578063bcbaf4871461057857600080fd5b80638eba35351461045d57806392aac701146104705780639d2f053c146104835780639f0a54591461049657600080fd5b806358171a61116101925780635dedde6d116101615780635dedde6d1461041b578063640d0c28146104245780636c629159146104375780638607f5c31461044a57600080fd5b806358171a611461038457806359968288146103a75780635ad7226f146103ba5780635b6df29a146103cd57600080fd5b806337a7b7d8116101ce57806337a7b7d81461024157806346322c3714610280578063514ea4bf146102955780635312ea8e1461037157600080fd5b806309163014146102005780632acb38101461021c5780632eda95c2146102255780633197e19214610238575b600080fd5b61020960105481565b6040519081526020015b60405180910390f35b61020960115481565b6102096102333660046146a3565b61063a565b61020960195481565b6102687f000000000000000000000000ffdd8e8d16aed8cadf4b46dcaf4ba620dc269de181565b6040516001600160a01b039091168152602001610213565b61029361028e3660046146d0565b6106d4565b005b6103136102a33660046146fc565b601660205260009081526040902080546001909101546001600160601b0380831692600160601b810490911691600160c01b8204600290810b92600160d81b810490910b91600160f01b80830460ff90811693600160f81b900416916001600160f01b03811691900461ffff1688565b604080516001600160601b03998a168152989097166020890152600295860b968801969096529290930b60608601521515608085015290151560a08401526001600160f01b031660c083015261ffff1660e082015261010001610213565b61029361037f3660046146fc565b610dfb565b610397610392366004614715565b611008565b6040519015158152602001610213565b6102096103b5366004614732565b611074565b6102936103c8366004614771565b611624565b6015546103f59063ffffffff80821691600160201b810490911690600160401b900460170b83565b6040805163ffffffff948516815293909216602084015260170b90820152606001610213565b610209600f5481565b6102936104323660046147f0565b611847565b610209610445366004614715565b6118bb565b6102096104583660046146a3565b6118e9565b61020961046b366004614820565b611973565b61020961047e366004614715565b611988565b6102096104913660046146fc565b611a0e565b6104a96104a43660046146d0565b611a25565b60408051928352602083019190915201610213565b6104c6611b77565b6040516102139190600061010082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e0830151151560e083015292915050565b6102687f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f781565b6013546103f59063ffffffff80821691600160201b810490911690600160401b900460170b83565b610293610586366004614857565b611c98565b6102096105993660046146fc565b612196565b601a546103979060ff1681565b6102687f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea3381565b61020960185481565b6102096105e9366004614889565b612204565b6014546103f59063ffffffff80821691600160201b810490911690600160401b900460170b83565b6102096106243660046146a3565b612288565b61020960125481565b6102936122be565b600061064e83606001518460800151612338565b9050600061065d81600261234f565b9050600061066c81600161234f565b9050600061067a828661237d565b610684908461492b565b90506801158e460913d0000081106106b75760405162461bcd60e51b81526004016106ae90614943565b60405180910390fd5b6106ca6106c3826123cc565b859061237d565b9695505050505050565b601a5460ff16156106f75760405162461bcd60e51b81526004016106ae9061496f565b670de0b6b3a76400008211156107445760405162461bcd60e51b815260206004820152601260248201527109eac98ac6274cce4c2c6e8d2dedc7cdac2f60731b60448201526064016106ae565b61075961075083612467565b61ffff166124e0565b9150600082116107a05760405162461bcd60e51b815260206004820152601260248201527127ab262b189d333930b1ba34b7b71e36b4b760711b60448201526064016106ae565b60008060008060006107b0611b77565b905060006107c06016338b612507565b90506107cb81612620565b6107e75760405162461bcd60e51b81526004016106ae90614998565b600081608001516107fa576010546107fe565b600f545b90506000826080015161081357601254610817565b6011545b905061085782826108278761263d565b6108336000600361234f565b61083f6000600861234f565b61084b6000600a61234f565b89959493929190612651565b156108995760405162461bcd60e51b81526020600482015260126024820152714f564c56313a6c6971756964617461626c6560701b60448201526064016106ae565b60006108b66108ad8661062484600461234f565b61046b8761263d565b905083608001516108eb576108e685610233876108e08f88888b6126da909392919063ffffffff16565b85612717565b610910565b610910856104588761090a8f88888b6126da909392919063ffffffff16565b856127de565b965083608001516109245789871115610929565b898710155b6109455760405162461bcd60e51b81526004016106ae90614943565b600061095281600361234f565b9050610962858d86868c866128a0565b995061096e858d6129ac565b9850600061097d81600b61234f565b905061098e868e87878d87876129d4565b975061099a888c6129fe565b97508560800151156109e7576109be6109b5878f88886126da565b600f5490612a0d565b600f556109cb868e612a28565b601160008282546109dc91906149c1565b90915550610a239050565b6109ff6109f6878f88886126da565b60105490612a0d565b601055610a0c868e612a28565b60126000828254610a1d91906149c1565b90915550505b610a35610a308b8d6149d8565b612a4b565b50610a40868e612a28565b8660c001818151610a519190614a17565b6001600160f01b0316905250610a67868e612b09565b8660e0019061ffff16908161ffff1681525050610a92338f886016612b83909392919063ffffffff16565b50505050505050336001600160a01b03167fc13b78a0772a556b5387d497953273371ed42cff2af20c019d9f119a737685ba88888688610ad291906149d8565b604080519384526020840192909252908201526060810185905260800160405180910390a2828410610b9b576001600160a01b037f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f7166340c10f1930610b3886886149c1565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015610b7e57600080fd5b505af1158015610b92573d6000803e3d6000fd5b50505050610c25565b6001600160a01b037f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f7166342966c68610bd486866149c1565b6040518263ffffffff1660e01b8152600401610bf291815260200190565b600060405180830381600087803b158015610c0c57600080fd5b505af1158015610c20573d6000803e3d6000fd5b505050505b6001600160a01b037f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f71663a9059cbb33610c5f84886149c1565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610caa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cce9190614a3f565b507f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f76001600160a01b031663a9059cbb7f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea336001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d809190614a5c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df19190614a3f565b5050505050505050565b601a5460ff16610e405760405162461bcd60e51b815260206004820152601060248201526f27ab262b189d1010b9b43aba3237bbb760811b60448201526064016106ae565b6000610e4e60163384612507565b9050610e5981612620565b610e755760405162461bcd60e51b81526004016106ae90614998565b670de0b6b3a76400006000610e8a83836129ac565b6040516370a0823160e01b8152306004820152909150610f1f906001600160a01b037f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f716906370a0823190602401602060405180830381865afa158015610ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f199190614a79565b826129fe565b600060e08501529050610f356016338686612b83565b604080518581526020810183905233917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595910160405180910390a260405163a9059cbb60e01b8152336004820152602481018290527f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f76001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610fdd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110019190614a3f565b5050505050565b60195460009081611021670de0b6b3a764000083612ca8565b608085015160a08601519192509080158061103a575081155b1561104b5750600095945050505050565b60006110578383612cd7565b90508381101580156110695750848111155b979650505050505050565b601a5460009060ff161561109a5760405162461bcd60e51b81526004016106ae9061496f565b670de0b6b3a76400008410156110e25760405162461bcd60e51b815260206004820152600d60248201526c27ab262b189d3632bb1e36b4b760991b60448201526064016106ae565b6110ee6000600561234f565b84111561112d5760405162461bcd60e51b815260206004820152600d60248201526c09eac98ac6274d8caec7cdac2f609b1b60448201526064016106ae565b6111396000600c61234f565b85101561117f5760405162461bcd60e51b815260206004820152601460248201527327ab262b189d31b7b63630ba32b930b61e36b4b760611b60448201526064016106ae565b600080600080600061118f611b77565b9050600061119d8b8b61237d565b905060006111aa8361263d565b90506111b68282611973565b9650600087116111f65760405162461bcd60e51b815260206004820152600b60248201526a04f564c56313a6f693d3d360ac1b60448201526064016106ae565b6112008c836149c1565b95506112186112116000600b61234f565b839061237d565b9350600061123461122e8561062484600461234f565b83611973565b90508a61124f5761124a84610458868b856127de565b61125e565b61125e84610233868b85612717565b95508a61126e5789861015611273565b898611155b61128f5760405162461bcd60e51b81526004016106ae90614943565b600061129c89838e612d08565b90506000604051806101000160405280866001600160601b031681526020018a6001600160601b031681526020016112d386612dd1565b60020b81526020016112e48a612dd1565b60020b81528e15156020820152600060408201526001600160f01b038416606082015260800161131b670de0b6b3a7640000612467565b61ffff16905290506113798d61133357601054611337565b600f545b8e61134457601254611348565b6011545b866113556000600361234f565b6113616000600861234f565b61136d6000600a61234f565b87959493929190612651565b156113bb5760405162461bcd60e51b81526020600482015260126024820152714f564c56313a6c6971756964617461626c6560701b60448201526064016106ae565b6017549a506113cd6016338d84612b83565b601780549060006113dd83614a92565b9091555050604080518c8152602081018c90529081018a90528d15156060820152608081018990523396507fb98b46cc473761b09478db481c36070133bf6b7a18241892f5477e725b063b5a955060a001935061143992505050565b60405180910390a26001600160a01b037f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f7166323b872dd333061147c858e61492b565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af11580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614a3f565b507f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f76001600160a01b031663a9059cbb7f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea336001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a69190614a5c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156115f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116179190614a3f565b5050505050949350505050565b336001600160a01b037f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea33161461166c5760405162461bcd60e51b81526004016106ae90614aad565b60007f000000000000000000000000ffdd8e8d16aed8cadf4b46dcaf4ba620dc269de16001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa1580156116cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f19190614ad6565b905060006116fe8261263d565b116117395760405162461bcd60e51b815260206004820152600b60248201526a4f564c56313a216461746160a81b60448201526064016106ae565b4260185560a0820151604083015161010084015161014085015161179661177261176b83670de0b6b3a76400006149c1565b8490612ca8565b61177d856002614b9c565b611787919061492b565b670de0b6b3a764000090612ca8565b8411156117b55760405162461bcd60e51b81526004016106ae90614bbb565b6101a086015160408601516801158e460913d00000906117d59083614b9c565b106117f25760405162461bcd60e51b81526004016106ae90614c02565b6117fd600d82612e67565b60005b600f811015610df1578781600f811061181b5761181b614b86565b6020020151600082600f811061183357611833614b86565b01558061183f81614a92565b915050611800565b336001600160a01b037f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea33161461188f5760405162461bcd60e51b81526004016106ae90614aad565b611897612f32565b6118a18282612fb6565b6118ab8282612e67565b6118b7600083836132c0565b5050565b6000806118c981600161234f565b90506118e28360c00151826132eb90919063ffffffff16565b9392505050565b60006118fd836060015184608001516129fe565b9050600061190c81600261234f565b9050600061191b81600161234f565b90506000611929828661237d565b611933908461492b565b90506801158e460913d00000811061195d5760405162461bcd60e51b81526004016106ae90614943565b6106ca61196c611787836123cc565b85906132eb565b600061197f8383612ca8565b90505b92915050565b60008061199681600e61234f565b9050600081670de0b6b3a764000085604001516119b39190614b9c565b6119bd9190614c5a565b905060006119cc81600261234f565b9050611a056119e4670de0b6b3a76400006002614b9c565b6119ff846119ff8960c00151866132eb90919063ffffffff16565b906132eb565b95945050505050565b600081600f8110611a1e57600080fd5b0154905081565b60008080611a33858761492b565b90506000611a4186886149c1565b90506000611a4f878961237d565b9050821580611a5c575081155b15611a6f57878794509450505050611b6f565b60008087611a7d828061234f565b611a88906002614b9c565b611a929190614b9c565b90506801158e460913d00000811015611ab457611ab1611787826123cc565b91505b6000611ac08587612ca8565b90506000611aed611ad185806132eb565b611ae390670de0b6b3a76400006149c1565b6119ff84806132eb565b611aff90670de0b6b3a76400006149c1565b9050611b28611b21611b1a6002670de0b6b3a7640000614c5a565b839061330c565b88906132eb565b9650611b3486856132eb565b95506002611b42878961492b565b611b4c9190614c5a565b9b508b15611b6157611b5e858d612cd7565b9a505b8b8b98509850505050505050505b935093915050565b611bc1604051806101000160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b611bc9612f32565b60007f000000000000000000000000ffdd8e8d16aed8cadf4b46dcaf4ba620dc269de16001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa158015611c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4e9190614ad6565b9050611c5981611008565b611c935760405162461bcd60e51b815260206004820152600b60248201526a4f564c56313a216461746160a81b60448201526064016106ae565b919050565b601a5460ff1615611cbb5760405162461bcd60e51b81526004016106ae9061496f565b6000808080808080611ccf60168a8a612507565b9050611cda81612620565b611cf65760405162461bcd60e51b81526004016106ae90614998565b6000611d00611b77565b905060008260800151611d1557601054611d19565b600f545b905060008360800151611d2e57601254611d32565b6011545b90506000611d4181600361234f565b9050670de0b6b3a7640000611d558561263d565b9950611d8284848c85611d6a6000600861234f565b611d766000600a61234f565b8c959493929190612651565b611dc45760405162461bcd60e51b81526020600482015260136024820152724f564c56313a216c6971756964617461626c6560681b60448201526064016106ae565b611dd2868286868e876128a0565b9b50611dde86826129ac565b9a50611df6611def6000600a61234f565b8d906132eb565b9850611e02898d6149c1565b9650611e13611b216000600961234f565b9750611e1f88886149c1565b9650856080015115611e6357611e3a6109b5878387876126da565b600f55611e478682612a28565b60116000828254611e5891906149c1565b90915550611e969050565b611e726109f6878387876126da565b601055611e7f8682612a28565b60126000828254611e9091906149c1565b90915550505b611eae88611ea48d8f6149d8565b610a3091906149d8565b50600160a0870152600060c0870181905260e0870152611ed160168f8f89612b83565b505050505050876001600160a01b0316336001600160a01b03167ff1deb4d6391f20e8cad919356063127cf8453da1fdf246eb1b5e4549e848112e8985898b611f1a91906149d8565b611f2491906149d8565b604080519283526020830191909152810188905260600160405180910390a36001600160a01b037f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f7166342966c6883611f7d89896149c1565b611f87919061492b565b6040518263ffffffff1660e01b8152600401611fa591815260200190565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b505060405163a9059cbb60e01b8152336004820152602481018690527f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f76001600160a01b0316925063a9059cbb91506044016020604051808303816000875af1158015612044573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120689190614a3f565b507f000000000000000000000000dc77acc82cce1cc095cba197474cc06824ade6f76001600160a01b031663a9059cbb7f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea336001600160a01b031663469048406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211a9190614a5c565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015612167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218b9190614a3f565b505050505050505050565b6040805160608101825260155463ffffffff8082168352600160201b820481166020840152600160401b90910460170b9282019290925260009182906121e190829060069061234f16565b90506121f082428360006133fe565b91506121fc8285612204565b949350505050565b600080612215846040015160170b90565b9050600061222481600761234f565b9050808213612237578392505050611982565b612242816002614c6e565b821261225357600092505050611982565b600061225f8383612ca8565b612272670de0b6b3a76400006002614b9c565b61227c91906149c1565b90506106ca85826132eb565b60008260e00151156122b8576122a6826122a1856118bb565b6129fe565b91506122b5826122a185611988565b91505b50919050565b601a5460ff16156122e15760405162461bcd60e51b81526004016106ae9061496f565b336001600160a01b037f0000000000000000000000009a74758c2a80fa1b1d899e0e1f24cf505a4dea3316146123295760405162461bcd60e51b81526004016106ae90614aad565b601a805460ff19166001179055565b600081831015612348578161197f565b5090919050565b60008282600e81111561236457612364614b70565b600f811061237457612374614b86565b01549392505050565b60008061238a8385614b9c565b90508061239b576000915050611982565b670de0b6b3a76400006123af6001836149c1565b6123b99190614c5a565b6123c490600161492b565b915050611982565b6000816123e25750670de0b6b3a7640000919050565b600160ff1b82106124355760405162461bcd60e51b815260206004820152601b60248201527f4669786564506f696e743a2078206f7574206f6620626f756e6473000000000060448201526064016106ae565b816000612441826135fa565b9050600061245b6124548361271061237d565b60016139dc565b9050611a0582826139dc565b60008061247e612710670de0b6b3a7640000614c5a565b9050600061248c8285614c5a565b905061ffff8111156118e25760405162461bcd60e51b815260206004820152601e60248201527f4f564c56313a20466978656443617374206f7574206f6620626f756e6473000060448201526064016106ae565b6000806124f7612710670de0b6b3a7640000614c5a565b90506118e28161ffff8516614b9c565b60408051610100810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e090930182905283519590921b6bffffffffffffffffffffffff1916858301526034808601949094528251808603909401845260548501808452845194830194909420815294905292839020610154830190935282546001600160601b038082168352600160601b8204166074840152600160c01b8104600290810b6094850152600160d81b8204900b60b4840152600160f01b80820460ff908116151560d4860152600160f81b909204909116151560f48401526001909301546001600160f01b0381166101148401529290920461ffff166101349091015290565b60008160a0015115801561198257505060e0015161ffff16151590565b6000611982826060015183608001516139e9565b6000670de0b6b3a7640000816126678a83613a04565b90508960a001518061267f575060e08a015161ffff16155b1561268f57600092505050611069565b600061269f8b848c8c8c8c6128a0565b905060006126ad838861237d565b905060006126bb83886132eb565b90506126c7818361492b565b9092109c9b505050505050505050505050565b6000806126e78686612a28565b90508015806126f4575083155b806126fd575082155b1561270c5760009150506121fc565b6106ca818585613a35565b6040805160608101825260145463ffffffff8082168352600160201b820481166020840152600160401b90910460170b9282019290925260009182906127619086908690612cd716565b60208701519091506127779083904290846133fe565b8051601480546020840151604085015163ffffffff94851667ffffffffffffffff1990931692909217600160201b94909116939093029290921767ffffffffffffffff16600160401b6001600160c01b0384160217905590925060170b9695505050505050565b6040805160608101825260135463ffffffff8082168352600160201b820481166020840152600160401b90910460170b9282019290925260009182906128289086908690612cd716565b602087015190915061283e9083904290846133fe565b8051601380546020840151604085015163ffffffff94851667ffffffffffffffff1990931692909217600160201b94909116939093029290921767ffffffffffffffff16600160401b6001600160c01b0384160217905590925060170b6106ca565b6000806128ad8888613ae8565b905060006128bb8989613a04565b905060006128c98a8a613b05565b905060006128d98b8b8b8b6126da565b905060006128e68c613b2d565b90508b6080015115612969576129246128ff838a61237d565b6122a16129148a670de0b6b3a764000061492b565b61291e868661237d565b9061237d565b61293886612932878661237d565b90612cd7565b612942919061492b565b9550612962612951838361237d565b61295b908561492b565b8790612a0d565b955061299d565b612973828261237d565b61298186612932878661237d565b61298b919061492b565b955061299a612951838a61237d565b95505b50505050509695505050505050565b6000806129b98484613a04565b905060006129c78585613b05565b9050816106ca8183612a0d565b6000806129e5898989898989613b3c565b90506129f1818461237d565b9998505050505050505050565b6000818310612348578161197f565b600080828411612a1e5760006121fc565b6121fc83856149c1565b600080612a3f8460c001516001600160f01b031690565b90506121fc81846132eb565b6040805160608101825260155463ffffffff8082168352600160201b820481166020840152600160401b90910460170b928201929092526000918290612a9690829060069061234f16565b9050612aa4824283876133fe565b8051601580546020840151604085015163ffffffff94851667ffffffffffffffff1990931692909217600160201b94909116939093029290921767ffffffffffffffff16600160401b6001600160c01b0384160217905590925060009060170b611a05565b6000670de0b6b3a7640000821115612b585760405162461bcd60e51b815260206004820152601260248201527109eac98ac6274cce4c2c6e8d2dedc7cdac2f60731b60448201526064016106ae565b6000612b78612b6f84670de0b6b3a76400006149c1565b6119ff86613b67565b90506121fc81612467565b6040516bffffffffffffffffffffffff19606085901b166020820152603481018390528190859060009060540160408051808303601f1901815291815281516020928301208352828201939093529082016000208351815492850151938501516060860151608087015160a08801516001600160601b039485166001600160c01b031990971696909617600160601b94909716939093029590951765ffffffffffff60c01b1916600160c01b62ffffff9283160262ffffff60d81b191617600160d81b9190951602939093176001600160f01b03908116600160f01b94151585026001600160f81b031617600160f81b9315159390930292909217815560c084015160e0909401519390911661ffff9093169091029190911760019091015550505050565b600082612cb757506000611982565b6000612ccb670de0b6b3a764000085614b9c565b90506123c48382614c5a565b600082612ce657506000611982565b6000612cfa670de0b6b3a764000085614b9c565b9050826123af6001836149c1565b60008082612d1857601054612d1c565b600f545b9050600083612d2d57601254612d31565b6011545b90506000612d40878484613b7a565b9050612d4c878461492b565b9250612d58818361492b565b91506000612d6587612196565b905080841115612da65760405162461bcd60e51b815260206004820152600c60248201526b04f564c56313a6f693e6361760a41b60448201526064016106ae565b8515612dbb57600f8490556011839055612dc6565b601084905560128390555b509695505050505050565b600080612de683670de111a6b7de4000613ba3565b90506956d225004ee68c3fffff198112158015612e0d575069fe1c215e8f838e0000008113155b612e555760405162461bcd60e51b81526020600482015260196024820152784f564c56313a207469636b206f7574206f6620626f756e647360381b60448201526064016106ae565b6118e2670de0b6b3a764000082614cf3565b600d82600e811115612e7b57612e7b614b70565b14156118b75760007f000000000000000000000000ffdd8e8d16aed8cadf4b46dcaf4ba620dc269de16001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa158015612ee2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f069190614ad6565b60408101519091508290600090612f1d9083614b9c565b9050612f28816123cc565b6019555050505050565b600060185442612f4291906149c1565b90508015612fb357601054600f5411600081612f6057601054612f64565b600f545b9050600082612f7557600f54612f79565b6010545b9050612f86828286611a25565b909250905082612f965780612f98565b815b600f5582612fa65781612fa8565b805b601055505042601855505b50565b600282600e811115612fca57612fca614b70565b141561304557806000612fde81600561234f565b90506000612fed81600861234f565b90506000612ffc81600a61234f565b905061302161301661176b83670de0b6b3a76400006149c1565b61177d866002614b9c565b8311156130405760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600582600e81111561305957613059614b70565b14156130c95780600061306d81600261234f565b9050600061307c81600861234f565b9050600061308b81600a61234f565b90506130a561177261176b83670de0b6b3a76400006149c1565b8411156130c45760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600882600e8111156130dd576130dd614b70565b1415613154578060006130f181600261234f565b9050600061310081600561234f565b9050600061310f81600a61234f565b905061313061177261312983670de0b6b3a76400006149c1565b8690612ca8565b82111561314f5760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600a82600e81111561316857613168614b70565b14156131df5780600061317c81600261234f565b9050600061318b81600561234f565b9050600061319a81600861234f565b90506131bb6117726131b486670de0b6b3a76400006149c1565b8390612ca8565b8211156131da5760405162461bcd60e51b81526004016106ae90614bbb565b505050505b600d82600e8111156131f3576131f3614b70565b14156118b75760007f000000000000000000000000ffdd8e8d16aed8cadf4b46dcaf4ba620dc269de16001600160a01b03166352bfe7896040518163ffffffff1660e01b815260040161010060405180830381865afa15801561325a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061327e9190614ad6565b604081015190915082906801158e460913d000009061329d9083614b9c565b106132ba5760405162461bcd60e51b81526004016106ae90614c02565b50505050565b808383600e8111156132d4576132d4614b70565b600f81106132e4576132e4614b86565b0155505050565b6000806132f88385614b9c565b90506121fc670de0b6b3a764000082614c5a565b60008115806133225750670de0b6b3a764000083145b156133365750670de0b6b3a7640000611982565b8261334357506000611982565b670de0b6b3a764000082141561335a575081611982565b61336d670de0b6b3a76400006002614b9c565b8214156133855761337e83846132eb565b9050611982565b613398670de0b6b3a76400006004614b9c565b8214156133b75760006133ab84856132eb565b90506123c481826132eb565b60006133c38484613cb2565b905060006133d66124548361271061237d565b9050808210156133eb57600092505050611982565b6133f58282613db3565b92505050611982565b6040805160608101825260008082526020820181905291810182905285519091859163ffffffff908116908316101561345b57865163ffffffff9081169061344c908416600160201b61492b565b61345691906149c1565b61346e565b86516134679083614d21565b63ffffffff165b602088015190915063ffffffff16600061348c896040015160170b90565b9050818310158061349b575081155b156134e55760405180606001604052808563ffffffff1681526020016134c089613dc0565b63ffffffff1681526020016134d488613dd9565b60170b8152509450505050506121fc565b816134f084826149c1565b6134fa9083614c6e565b6135049190614cf3565b905060006135128783614d3e565b9050806135565760405180606001604052808663ffffffff1681526020016135398a613dc0565b63ffffffff168152600060209091015295506121fc945050505050565b600061356183613e1c565b9050600061356e89613e1c565b9050600061357c828461492b565b6135868c84614b9c565b61359089896149c1565b61359a9086614b9c565b6135a4919061492b565b6135ae9190614c5a565b905060405180606001604052808963ffffffff1681526020016135d083613dc0565b63ffffffff1681526020016135e486613dd9565b60170b90529d9c50505050505050505050505050565b6000613629680238fd42c5cf03ffff198312158015613622575068070c1cc73b00c800008313155b6009613e33565b60008212156136615761363e826000036135fa565b6a0c097ce7bc90715b34b9f160241b8161365a5761365a614c44565b0592915050565b60006806f05b59d3b200000083126136a157506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec6302628270000000006136d7565b6803782dace9d900000083126136d357506803782dace9d8ffffff19909101906b1425982cf597cd205cef73806136d7565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac6200000084126137275768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613763576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b18800000841261379d57682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c40000084126137d7576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac6200000841261381057680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d6310000084126138495768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613882576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c4000084126138bb5768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b6000806121fc838561492b565b60006139f86002848418614c5a565b61197f9084841661492b565b600080613a1084613b67565b90506000613a298261291e87516001600160601b031690565b9050611a05818561237d565b600080806000198587098587029250828110838203039150508060001415613a6f5760008411613a6457600080fd5b5082900490506118e2565b808411613a7b57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b600080613af484613b67565b90506000613a298261291e87613e41565b600080613b1184613b67565b90506000613a298261291e87602001516001600160601b031690565b60006119828260600151613e6e565b600080613b4d8888888888886128a0565b90506000613b5b8989613b05565b90506129f1818361492b565b60006119828260e0015161ffff166124e0565b6000821580613b87575081155b613b9b57613b96848385613a35565b6121fc565b509192915050565b60008083118015613bb75750600160ff1b83105b613c035760405162461bcd60e51b815260206004820152601b60248201527f4669786564506f696e743a2061206f7574206f6620626f756e6473000000000060448201526064016106ae565b600082118015613c165750600160ff1b82105b613c625760405162461bcd60e51b815260206004820152601b60248201527f4669786564506f696e743a2062206f7574206f6620626f756e6473000000000060448201526064016106ae565b82826000613c708383613f33565b9050600080821215613c855781600003613c87565b815b90506000613c9a6124548361271061237d565b9050613ca681846149d8565b98975050505050505050565b600081613cc85750670de0b6b3a7640000611982565b82613cd557506000611982565b613ce6600160ff1b84106006613e33565b82613d0c770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007613e33565b826000670c7d713b49da000083138015613d2d5750670f43fc2c04ee000083125b15613d64576000613d3d84613fed565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050613d72565b81613d6e8461410c565b0290505b670de0b6b3a76400009005613daa680238fd42c5cf03ffff198212801590613da3575068070c1cc73b00c800008213155b6008613e33565b6106ca816135fa565b6000806121fc83856149c1565b60008063ffffffff8311156123485763ffffffff6118e2565b6000806001600160bf1b03198312613e0c576001600160bf1b038313613dff57826118e2565b6001600160bf1b036118e2565b6001600160bf1b03199392505050565b600080821215613e2f5781600003611982565b5090565b816118b7576118b7816144b6565b600080613e5583516001600160601b031690565b90506000613e6284614509565b90506121fc8282612ca8565b600080613e87670de0b6b3a7640000600285900b614c6e565b90506956d225004ee68c3fffff198112158015613eae575069fe1c215e8f838e0000008113155b613ef65760405162461bcd60e51b81526020600482015260196024820152784f564c56313a207469636b206f7574206f6620626f756e647360381b60448201526064016106ae565b6000613f0182613e1c565b90506000821215613f2157613b96611787670de111a6b7de400083614518565b6121fc670de111a6b7de40008261330c565b600080670c7d713b49da000083138015613f545750670f43fc2c04ee000083125b15613f6957613f6283613fed565b9050613f7f565b670de0b6b3a7640000613f7b8461410c565b0290505b6000670c7d713b49da000085138015613f9f5750670f43fc2c04ee000085125b15613fb457613fad85613fed565b9050613fca565b670de0b6b3a7640000613fc68661410c565b0290505b81670de0b6b3a7640000820281613fe357613fe3614c44565b0595945050505050565b670de0b6b3a7640000026000806a0c097ce7bc90715b34b9f160241b808401906ec097ce7bc90715b34b9f0fffffffff198501028161402e5761402e614c44565b05905060006a0c097ce7bc90715b34b9f160241b82800205905081806a0c097ce7bc90715b34b9f160241b81840205915060038205016a0c097ce7bc90715b34b9f160241b82840205915060058205016a0c097ce7bc90715b34b9f160241b82840205915060078205016a0c097ce7bc90715b34b9f160241b82840205915060098205016a0c097ce7bc90715b34b9f160241b828402059150600b8205016a0c097ce7bc90715b34b9f160241b828402059150600d8205016a0c097ce7bc90715b34b9f160241b828402059150600f82050160020295945050505050565b6000670de0b6b3a764000082121561414d57614144826a0c097ce7bc90715b34b9f160241b8161413e5761413e614c44565b0561410c565b60000392915050565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261419e57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126141d6576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261421e576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a7008312614259576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261429057693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126142c757690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126142fc5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261432757680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261435c576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312614391576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126143c5576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac83126143f9576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161442257614422614c44565b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006119828260400151613e6e565b600081158061452e5750670de0b6b3a764000083145b156145425750670de0b6b3a7640000611982565b8261454f57506000611982565b670de0b6b3a7640000821415614566575081611982565b614579670de0b6b3a76400006002614b9c565b82141561458a5761337e838461237d565b61459d670de0b6b3a76400006004614b9c565b8214156145bc5760006145b0848561237d565b90506123c4818261237d565b60006145c88484613cb2565b905060006145db6124548361271061237d565b90506133f582826139dc565b634e487b7160e01b600052604160045260246000fd5b8015158114612fb357600080fd5b600061010080838503121561461f57600080fd5b6040519081019067ffffffffffffffff82118183101715614642576146426145e7565b81604052809250833581526020840135602082015260408401356040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e08401359150614699826145fd565b60e0015292915050565b60008061012083850312156146b757600080fd5b6146c1848461460b565b94610100939093013593505050565b6000806000606084860312156146e557600080fd5b505081359360208301359350604090920135919050565b60006020828403121561470e57600080fd5b5035919050565b6000610100828403121561472857600080fd5b61197f838361460b565b6000806000806080858703121561474857600080fd5b84359350602085013592506040850135614761816145fd565b9396929550929360600135925050565b60006101e080838503121561478557600080fd5b83601f84011261479457600080fd5b60405181810181811067ffffffffffffffff821117156147b6576147b66145e7565b6040529083019080858311156147cb57600080fd5b845b838110156147e55780358252602091820191016147cd565b509095945050505050565b6000806040838503121561480357600080fd5b8235600f811061481257600080fd5b946020939093013593505050565b6000806040838503121561483357600080fd5b50508035926020909101359150565b6001600160a01b0381168114612fb357600080fd5b6000806040838503121561486a57600080fd5b823561481281614842565b803563ffffffff81168114611c9357600080fd5b600080828403608081121561489d57600080fd5b60608112156148ab57600080fd5b506040516060810181811067ffffffffffffffff821117156148cf576148cf6145e7565b6040526148db84614875565b81526148e960208501614875565b602082015260408401358060170b811461490257600080fd5b6040820152946060939093013593505050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561493e5761493e614915565b500190565b60208082526012908201527109eac98ac6274e6d8d2e0e0c2ceca7cdac2f60731b604082015260600190565b6020808252600f908201526e27ab262b189d1039b43aba3237bbb760891b604082015260600190565b6020808252600f908201526e27ab262b189d10b837b9b4ba34b7b760891b604082015260600190565b6000828210156149d3576149d3614915565b500390565b60008083128015600160ff1b8501841216156149f6576149f6614915565b6001600160ff1b0384018313811615614a1157614a11614915565b50500390565b60006001600160f01b0383811690831681811015614a3757614a37614915565b039392505050565b600060208284031215614a5157600080fd5b81516118e2816145fd565b600060208284031215614a6e57600080fd5b81516118e281614842565b600060208284031215614a8b57600080fd5b5051919050565b6000600019821415614aa657614aa6614915565b5060010190565b6020808252600f908201526e4f564c56313a2021666163746f727960881b604082015260600190565b6000610100808385031215614aea57600080fd5b6040519081019067ffffffffffffffff82118183101715614b0d57614b0d6145e7565b81604052835181526020840151602082015260408401516040820152606084015160608201526080840151608082015260a084015160a082015260c084015160c082015260e08401519150614b61826145fd565b60e08101919091529392505050565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6000816000190483118215151615614bb657614bb6614915565b500290565b60208082526027908201527f4f564c56313a206d6178206c657620696d6d6564696174656c79206c6971756960408201526664617461626c6560c81b606082015260800190565b60208082526022908201527f4f564c56313a2070726963652064726966742065786365656473206d61782065604082015261078760f41b606082015260800190565b634e487b7160e01b600052601260045260246000fd5b600082614c6957614c69614c44565b500490565b60006001600160ff1b0381841382841380821686840486111615614c9457614c94614915565b600160ff1b6000871282811687830589121615614cb357614cb3614915565b60008712925087820587128484161615614ccf57614ccf614915565b87850587128184161615614ce557614ce5614915565b505050929093029392505050565b600082614d0257614d02614c44565b600160ff1b821460001984141615614d1c57614d1c614915565b500590565b600063ffffffff83811690831681811015614a3757614a37614915565b600080821280156001600160ff1b0384900385131615614d6057614d60614915565b600160ff1b8390038412811615614d7957614d79614915565b5050019056fea2646970667358221220ee478acafbb18cfc986294a7b7b8431a058e742dfd924976abd552d038da8a6264736f6c634300080a0033

Deployed Bytecode Sourcemap

101566:40391:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102583:22;;;;;;;;;160:25:1;;;148:2;133:18;102583:22:0;;;;;;;;102612:27;;;;;;129267:553;;;;;;:::i;:::-;;:::i;103209:27::-;;;;;;102290:29;;;;;;;;-1:-1:-1;;;;;1880:32:1;;;1862:51;;1850:2;1835:18;102290:29:0;1716:203:1;111271:5528:0;;;;;;:::i;:::-;;:::i;:::-;;102996:59;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;102996:59:0;;;;-1:-1:-1;;;102996:59:0;;;;;;-1:-1:-1;;;102996:59:0;;;;;;;-1:-1:-1;;;102996:59:0;;;;;;-1:-1:-1;;;102996:59:0;;;;;;;;-1:-1:-1;;;102996:59:0;;;;-1:-1:-1;;;;;102996:59:0;;;;;;;;;;;;;-1:-1:-1;;;;;2810:15:1;;;2792:34;;2862:15;;;;2857:2;2842:18;;2835:43;2925:1;2914:21;;;2894:18;;;2887:49;;;;2972:21;;;;2967:2;2952:18;;2945:49;3038:14;3031:22;3025:3;3010:19;;3003:51;3098:14;;3091:22;3085:3;3070:19;;3063:51;-1:-1:-1;;;;;3151:32:1;3145:3;3130:19;;3123:61;3233:6;3221:19;3215:3;3200:19;;3193:48;2734:3;2719:19;102996:59:0;2430:817:1;141129:825:0;;;;;;:::i;:::-;;:::i;121861:870::-;;;;;;:::i;:::-;;:::i;:::-;;;3829:14:1;;3822:22;3804:41;;3792:2;3777:18;121861:870:0;3664:187:1;106955:4253:0;;;;;;:::i;:::-;;:::i;105479:1432::-;;;;;;:::i;:::-;;:::i;102883:46::-;;;;;;;;;;-1:-1:-1;;;102883:46:0;;;;;;-1:-1:-1;;;102883:46:0;;;;;;;;;;5299:10:1;5336:15;;;5318:34;;5388:15;;;;5383:2;5368:18;;5361:43;5451:2;5440:22;5420:18;;;5413:50;5277:2;5262:18;102883:46:0;5093:376:1;102555:21:0;;;;;;135412:336;;;;;;:::i;:::-;;:::i;127514:206::-;;;;;;:::i;:::-;;:::i;128630:569::-;;;;;;:::i;:::-;;:::i;128420:142::-;;;;;;:::i;:::-;;:::i;127865:391::-;;;;;;:::i;:::-;;:::i;102439:25::-;;;;;;:::i;:::-;;:::i;122942:2137::-;;;;;;:::i;:::-;;:::i;:::-;;;;6246:25:1;;;6302:2;6287:18;;6280:34;;;;6219:18;122942:2137:0;6072:248:1;121160:454:0;;;:::i;:::-;;;;;;6461:4:1;6503:3;6492:9;6488:19;6480:27;;6540:6;6534:13;6523:9;6516:32;6604:4;6596:6;6592:17;6586:24;6579:4;6568:9;6564:20;6557:54;6667:4;6659:6;6655:17;6649:24;6642:4;6631:9;6627:20;6620:54;6730:4;6722:6;6718:17;6712:24;6705:4;6694:9;6690:20;6683:54;6793:4;6785:6;6781:17;6775:24;6768:4;6757:9;6753:20;6746:54;6856:4;6848:6;6844:17;6838:24;6831:4;6820:9;6816:20;6809:54;6919:4;6911:6;6907:17;6901:24;6894:4;6883:9;6879:20;6872:54;6996:4;6988:6;6984:17;6978:24;6971:32;6964:40;6957:4;6946:9;6942:20;6935:70;6325:686;;;;;102234:36:0;;;;;102699:49;;;;;;;;;;-1:-1:-1;;;102699:49:0;;;;;;-1:-1:-1;;;102699:49:0;;;;;;116856:4149;;;;;;:::i;:::-;;:::i;125209:571::-;;;;;;:::i;:::-;;:::i;103316:22::-;;;;;;;;;102341:32;;;;;103140:34;;;;;;126121:673;;;;;;:::i;:::-;;:::i;102791:49::-;;;;;;;;;;-1:-1:-1;;;102791:49:0;;;;;;-1:-1:-1;;;102791:49:0;;;;;;126922:472;;;;;;:::i;:::-;;:::i;102646:28::-;;;;;;140848:89;;;:::i;129267:553::-;129342:12;129374:62;129383:4;:25;;;129410:4;:25;;;129374:8;:62::i;:::-;129367:69;-1:-1:-1;129522:13:0;129538:33;129522:13;129549:21;129538:10;:33::i;:::-;129522:49;-1:-1:-1;129582:13:0;129598:33;129582:13;129609:21;129598:10;:33::i;:::-;129582:49;-1:-1:-1;129642:11:0;129664:19;129582:49;129676:6;129664:11;:19::i;:::-;129656:27;;:5;:27;:::i;:::-;129642:41;;102201:5;129702:3;:26;129694:57;;;;-1:-1:-1;;;129694:57:0;;;;;;;:::i;:::-;;;;;;;;;129771:23;129782:11;:3;:9;:11::i;:::-;129771:4;;:10;:23::i;:::-;129764:30;129267:553;-1:-1:-1;;;;;;129267:553:0:o;111271:5528::-;103617:10;;;;103616:11;103608:39;;;;-1:-1:-1;;;103608:39:0;;;;;;;:::i;:::-;101986:4:::1;111419:8;:15;;111411:46;;;::::0;-1:-1:-1;;;111411:46:0;;9848:2:1;111411:46:0::1;::::0;::::1;9830:21:1::0;9887:2;9867:18;;;9860:30;-1:-1:-1;;;9906:18:1;;;9899:48;9964:18;;111411:46:0::1;9646:342:1::0;111411:46:0::1;111601:41;:24;:8;:22;:24::i;:::-;:39;;;:41::i;:::-;111590:52;;111672:1;111661:8;:12;111653:43;;;::::0;-1:-1:-1;;;111653:43:0;;10195:2:1;111653:43:0::1;::::0;::::1;10177:21:1::0;10234:2;10214:18;;;10207:30;-1:-1:-1;;;10253:18:1;;;10246:48;10311:18;;111653:43:0::1;9993:342:1::0;111653:43:0::1;111709:13;111733:12:::0;111756:13:::1;111780:18:::0;111908:23:::1;111934:8;:6;:8::i;:::-;111908:34:::0;-1:-1:-1;111997:24:0::1;112024:37;:9;112038:10;112050::::0;112024:13:::1;:37::i;:::-;111997:64;;112084:12;:3;:10;:12::i;:::-;112076:40;;;;-1:-1:-1::0;;;112076:40:0::1;;;;;;;:::i;:::-;112171:21;112195:3;:10;;;:29;;112217:7;;112195:29;;;112208:6;;112195:29;112171:53;;112239:27;112269:3;:10;;;:41;;112297:13;;112269:41;;;112282:12;;112269:41;112239:71;;112425:393;112464:13;112500:19;112542:18;112555:4;112542:12;:18::i;:::-;112617:37;:6;112628:25;112617:10;:37::i;:::-;112677:53;:6;112688:41;112677:10;:53::i;:::-;112753:46;:6;112764:34;112753:10;:46::i;:::-;112425:3:::0;;:393;;;;;:16:::1;:393::i;:::-;112424:394;112398:474;;;::::0;-1:-1:-1;;;112398:474:0;;10886:2:1;112398:474:0::1;::::0;::::1;10868:21:1::0;10925:2;10905:18;;;10898:30;-1:-1:-1;;;10944:18:1;;;10937:48;11002:18;;112398:474:0::1;10684:342:1::0;112398:474:0::1;113201:13;113217:160;113250:75;113279:4:::0;113285:39:::1;113201:13:::0;113296:27:::1;113285:10;:39::i;113250:75::-;113344:18;113357:4;113344:12;:18::i;113217:160::-;113201:176;;113400:3;:10;;;:574;;113712:262;113738:4;113765:190;113810:4;113841:59;113855:8;113865:13;113880:19;113841:3;:13;;:59;;;;;;:::i;:::-;113927:5;113765:18;:190::i;113712:262::-;113400:574;;;113430:262;113456:4;113483:190;113528:4;113559:59;113573:8;113583:13;113598:19;113559:3;:13;;:59;;;;;;:::i;:::-;113645:5;113483:18;:190::i;113430:262::-;113392:582;;114083:3;:10;;;:54;;114127:10;114118:5;:19;;114083:54;;;114105:10;114096:5;:19;;114083:54;114075:85;;;;-1:-1:-1::0;;;114075:85:0::1;;;;;;;:::i;:::-;114300:17;114320:37;114300:17:::0;114331:25:::1;114320:10;:37::i;:::-;114300:57:::0;-1:-1:-1;114380:73:0::1;:3:::0;114390:8;114400:13;114415:19;114436:5;114300:57;114380:9:::1;:73::i;:::-;114372:81:::0;-1:-1:-1;114475:18:0::1;:3:::0;114484:8;114475::::1;:18::i;:::-;114468:25:::0;-1:-1:-1;114569:22:0::1;114594:42;114569:22:::0;114605:30:::1;114594:10;:42::i;:::-;114569:67:::0;-1:-1:-1;114664:211:0::1;:3:::0;114697:8;114724:13;114756:19;114794:5;114818:9;114569:67;114664:14:::1;:211::i;:::-;114651:224;;114903:27;114912:10;114924:5;114903:8;:27::i;:::-;114890:40;;115190:3;:10;;;115186:473;;;115230:116;115268:59;:3:::0;115282:8;115292:13;115307:19;115268:13:::1;:59::i;:::-;115230:6;::::0;;:15:::1;:116::i;:::-;115221:6;:125:::0;115381:29:::1;:3:::0;115401:8;115381:19:::1;:29::i;:::-;115365:12;;:45;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;115186:473:0::1;::::0;-1:-1:-1;115186:473:0::1;;115461:117;115500:59;:3:::0;115514:8;115524:13;115539:19;115500:13:::1;:59::i;:::-;115461:7;::::0;;:16:::1;:117::i;:::-;115451:7;:127:::0;115614:29:::1;:3:::0;115634:8;115614:19:::1;:29::i;:::-;115597:13;;:46;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;115186:473:0::1;115800:49;115820:28;115843:4:::0;115827:5;115820:28:::1;:::i;:::-;115800:19;:49::i;:::-;-1:-1:-1::0;116027:29:0::1;:3:::0;116047:8;116027:19:::1;:29::i;:::-;116003:3;:12;;:54;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;116003:54:0::1;::::0;;-1:-1:-1;116096:38:0::1;:3:::0;116125:8;116096:28:::1;:38::i;:::-;116072:3;:21;;:62;;;;;;;;;::::0;::::1;116149:42;116163:10;116175;116187:3;116149:9;:13;;:42;;;;;;:::i;:::-;111843:4360;;;;;;;116257:10;-1:-1:-1::0;;;;;116250:77:0::1;;116269:10;116281:8;116314:4;116298:5;116291:28;;;;:::i;:::-;116250:77;::::0;;11898:25:1;;;11954:2;11939:18;;11932:34;;;;11982:18;;;11975:34;12040:2;12025:18;;12018:34;;;11885:3;11870:19;116250:77:0::1;;;;;;;116403:4;116394:5;:13;116390:138;;-1:-1:-1::0;;;;;116424:3:0::1;:8;;116441:4;116448:12;116456:4:::0;116448:5;:12:::1;:::i;:::-;116424:37;::::0;-1:-1:-1;;;;;;116424:37:0::1;::::0;;;;;;-1:-1:-1;;;;;12255:32:1;;;116424:37:0::1;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;12210:18;;116424:37:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;116390:138;;;-1:-1:-1::0;;;;;116494:3:0::1;:8;;116503:12;116510:5:::0;116503:4;:12:::1;:::i;:::-;116494:22;;;;;;;;;;;;;160:25:1::0;;148:2;133:18;;14:177;116494:22:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;116390:138;-1:-1:-1::0;;;;;116612:3:0::1;:12;;116625:10;116637:18;116645:10:::0;116637:5;:18:::1;:::i;:::-;116612:44;::::0;-1:-1:-1;;;;;;116612:44:0::1;::::0;;;;;;-1:-1:-1;;;;;12255:32:1;;;116612:44:0::1;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;12210:18;;116612:44:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;116724:3;-1:-1:-1::0;;;;;116724:12:0::1;;116755:7;-1:-1:-1::0;;;;;116737:39:0::1;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;116724:67;::::0;-1:-1:-1;;;;;;116724:67:0::1;::::0;;;;;;-1:-1:-1;;;;;12255:32:1;;;116724:67:0::1;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;;;12210:18;;116724:67:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;111400:5399;;;;111271:5528:::0;;;:::o;141129:825::-;103759:10;;;;103751:39;;;;-1:-1:-1;;;103751:39:0;;13050:2:1;103751:39:0;;;13032:21:1;13089:2;13069:18;;;13062:30;-1:-1:-1;;;13108:18:1;;;13101:46;13164:18;;103751:39:0;12848:340:1;103751:39:0;141242:24:::1;141269:37;:9;141283:10;141295::::0;141269:13:::1;:37::i;:::-;141242:64;;141325:12;:3;:10;:12::i;:::-;141317:40;;;;-1:-1:-1::0;;;141317:40:0::1;;;;;;;:::i;:::-;101986:4;141430:16;141478:18;:3:::0;101986:4;141478:8:::1;:18::i;:::-;141523:28;::::0;-1:-1:-1;;;141523:28:0;;141545:4:::1;141523:28;::::0;::::1;1862:51:1::0;141463:33:0;;-1:-1:-1;141514:44:0::1;::::0;-1:-1:-1;;;;;141523:3:0::1;:13;::::0;::::1;::::0;1835:18:1;;141523:28:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141553:4;141514:8;:44::i;:::-;141688:1;141664:21;::::0;::::1;:25:::0;141507:51;-1:-1:-1;141700:42:0::1;:9;141714:10;141726::::0;141664:3;141700:13:::1;:42::i;:::-;141792:47;::::0;;6246:25:1;;;6302:2;6287:18;;6280:34;;;141810:10:0::1;::::0;141792:47:::1;::::0;6219:18:1;141792:47:0::1;;;;;;;141916:30;::::0;-1:-1:-1;;;141916:30:0;;141929:10:::1;141916:30;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;;;141916:3:0::1;-1:-1:-1::0;;;;;141916:12:0::1;::::0;::::1;::::0;12210:18:1;;141916:30:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;141197:757;;;141129:825:::0;:::o;121861:870::-;122043:12;;121928:4;;;122090:26;101986:4;122043:12;122090:11;:26::i;:::-;122268:25;;;;122324:27;;;;122066:50;;-1:-1:-1;122268:25:0;122366:14;;;:31;;-1:-1:-1;122384:13:0;;122366:31;122362:127;;;-1:-1:-1;122472:5:0;;121861:870;-1:-1:-1;;;;;121861:870:0:o;122362:127::-;122623:10;122636:25;:8;122651:9;122636:14;:25::i;:::-;122623:38;;122686:13;122680:2;:19;;:42;;;;;122709:13;122703:2;:19;;122680:42;122672:51;121861:870;-1:-1:-1;;;;;;;121861:870:0:o;106955:4253::-;103617:10;;107114:19;;103617:10;;103616:11;103608:39;;;;-1:-1:-1;;;103608:39:0;;;;;;;:::i;:::-;101986:4:::1;107154:8;:15;;107146:41;;;::::0;-1:-1:-1;;;107146:41:0;;13584:2:1;107146:41:0::1;::::0;::::1;13566:21:1::0;13623:2;13603:18;;;13596:30;-1:-1:-1;;;13642:18:1;;;13635:43;13695:18;;107146:41:0::1;13382:337:1::0;107146:41:0::1;107218:39;:6;107229:27;107218:10;:39::i;:::-;107206:8;:51;;107198:77;;;::::0;-1:-1:-1;;;107198:77:0;;13926:2:1;107198:77:0::1;::::0;::::1;13908:21:1::0;13965:2;13945:18;;;13938:30;-1:-1:-1;;;13984:18:1;;;13977:43;14037:18;;107198:77:0::1;13724:337:1::0;107198:77:0::1;107308:41;:6;107319:29;107308:10;:41::i;:::-;107294:10;:55;;107286:88;;;::::0;-1:-1:-1;;;107286:88:0;;14268:2:1;107286:88:0::1;::::0;::::1;14250:21:1::0;14307:2;14287:18;;;14280:30;-1:-1:-1;;;14326:18:1;;;14319:50;14386:18;;107286:88:0::1;14066:344:1::0;107286:88:0::1;107387:10;107408:12:::0;107431:13:::1;107455:18:::0;107583:23:::1;107609:8;:6;:8::i;:::-;107583:34:::0;-1:-1:-1;107772:16:0::1;107791:26;:10:::0;107808:8;107791:16:::1;:26::i;:::-;107772:45;;107832:16;107851:18;107864:4;107851:12;:18::i;:::-;107832:37;;107889:34;107904:8;107914;107889:14;:34::i;:::-;107884:39;;108021:1;108016:2;:6;108008:30;;;::::0;-1:-1:-1;;;108008:30:0;;14617:2:1;108008:30:0::1;::::0;::::1;14599:21:1::0;14656:2;14636:18;;;14629:30;-1:-1:-1;;;14675:18:1;;;14668:41;14726:18;;108008:30:0::1;14415:335:1::0;108008:30:0::1;108191:21;108202:10:::0;108191:8;:21:::1;:::i;:::-;108184:28:::0;-1:-1:-1;108240:58:0::1;108255:42;:6;108266:30;108255:10;:42::i;:::-;108240:8:::0;;:14:::1;:58::i;:::-;108227:71:::0;-1:-1:-1;108460:13:0::1;108476:150;108509:75;108538:4:::0;108544:39:::1;108460:13:::0;108555:27:::1;108544:10;:39::i;108509:75::-;108603:8;108476:14;:150::i;:::-;108460:166;;108831:6;:138;;108923:46;108927:4;108933:35;108952:4;108958:2;108962:5;108933:18;:35::i;108923:46::-;108831:138;;;108857:46;108861:4;108867:35;108886:4;108892:2;108896:5;108867:18;:35::i;108857:46::-;108823:146;;109078:6;:50;;109118:10;109109:5;:19;;109078:50;;;109096:10;109087:5;:19;;109078:50;109070:81;;;;-1:-1:-1::0;;;109070:81:0::1;;;;;;;:::i;:::-;109306:16;109325:37;109344:2;109348:5;109355:6;109325:18;:37::i;:::-;109306:56;;109503:24;109530:495;;;;;;;;109587:8;-1:-1:-1::0;;;;;109530:495:0::1;;;;;109680:4;-1:-1:-1::0;;;;;109530:495:0::1;;;;;109713:26;109730:8;109713:16;:26::i;:::-;109530:495;;;;;;109769:23;109786:5;109769:16;:23::i;:::-;109530:495;;::::0;;;::::1;;;::::0;::::1;::::0;-1:-1:-1;109530:495:0;;;;-1:-1:-1;;;;;109530:495:0;::::1;::::0;;;;;;109990:19:::1;101986:4;109990:17;:19::i;:::-;109530:495;;::::0;;109503:522;-1:-1:-1;110067:413:0::1;110106:6:::0;:25:::1;;110124:7;;110106:25;;;110115:6;;110106:25;110154:6;:37;;110178:13;;110154:37;;;110163:12;;110154:37;110214:8:::0;110279:37:::1;:6;110290:25;110279:10;:37::i;:::-;110339:53;:6;110350:41;110339:10;:53::i;:::-;110415:46;:6;110426:34;110415:10;:46::i;:::-;110067:3:::0;;:413;;;;;:16:::1;:413::i;:::-;110066:414;110040:494;;;::::0;-1:-1:-1;;;110040:494:0;;10886:2:1;110040:494:0::1;::::0;::::1;10868:21:1::0;10925:2;10905:18;;;10898:30;-1:-1:-1;;;10944:18:1;;;10937:48;11002:18;;110040:494:0::1;10684:342:1::0;110040:494:0::1;110610:15;::::0;;-1:-1:-1;110640:43:0::1;:9;110654:10;110610:15:::0;110679:3;110640:13:::1;:43::i;:::-;110698:15;:17:::0;;;:15:::1;:17;::::0;::::1;:::i;:::-;::::0;;;-1:-1:-1;;110773:55:0::1;::::0;;15148:25:1;;;15204:2;15189:18;;15182:34;;;15232:18;;;15225:34;;;15302:14;;15295:22;15290:2;15275:18;;15268:50;15349:3;15334:19;;15327:35;;;110779:10:0::1;::::0;-1:-1:-1;110773:55:0::1;::::0;-1:-1:-1;15135:3:1;15120:19;;-1:-1:-1;110773:55:0::1;::::0;-1:-1:-1;;;14895:473:1;110773:55:0::1;;;;;;;;-1:-1:-1::0;;;;;110997:3:0::1;:16;;111014:10;111034:4;111041:23;111054:10:::0;111041;:23:::1;:::i;:::-;110997:68;::::0;-1:-1:-1;;;;;;110997:68:0::1;::::0;;;;;;-1:-1:-1;;;;;15631:15:1;;;110997:68:0::1;::::0;::::1;15613:34:1::0;15683:15;;;;15663:18;;;15656:43;15715:18;;;15708:34;15548:18;;110997:68:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;111133:3;-1:-1:-1::0;;;;;111133:12:0::1;;111164:7;-1:-1:-1::0;;;;;111146:39:0::1;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;111133:67;::::0;-1:-1:-1;;;;;;111133:67:0::1;::::0;;;;;;-1:-1:-1;;;;;12255:32:1;;;111133:67:0::1;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;;;12210:18;;111133:67:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;107135:4073;;;;106955:4253:::0;;;;;;:::o;105479:1432::-;103449:10;-1:-1:-1;;;;;103463:7:0;103449:21;;103441:49;;;;-1:-1:-1;;;103441:49:0;;;;;;;:::i;:::-;105594:23:::1;105635:4;-1:-1:-1::0;;;;;105620:27:0::1;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;105594:55;;105689:1;105668:18;105681:4;105668:12;:18::i;:::-;:22;105660:46;;;::::0;-1:-1:-1;;;105660:46:0;;17250:2:1;105660:46:0::1;::::0;::::1;17232:21:1::0;17289:2;17269:18;;;17262:30;-1:-1:-1;;;17308:18:1;;;17301:41;17359:18;;105660:46:0::1;17048:335:1::0;105660:46:0::1;105739:15;105717:19;:37:::0;105826:45;;::::1;::::0;105899:39;;::::1;::::0;105986:83;;::::1;::::0;106110:52;;::::1;::::0;106228:127:::1;106275:61;106310:25;106110:52:::0;101986:4:::1;106310:25;:::i;:::-;106275:26:::0;;:34:::1;:61::i;:::-;106262:10;106266:6:::0;106262:1:::1;:10;:::i;:::-;:74;;;;:::i;:::-;101986:4;::::0;106228:11:::1;:127::i;:::-;106195:12;:160;;106173:249;;;;-1:-1:-1::0;;;106173:249:0::1;;;;;;;:::i;:::-;106467:54:::0;;::::1;::::0;106578:16:::1;::::0;::::1;::::0;102201:5:::1;::::0;106554:40:::1;::::0;106467:54;106554:40:::1;:::i;:::-;:63;106532:147;;;;-1:-1:-1::0;;;106532:147:0::1;;;;;;;:::i;:::-;106690:75;106705:36;106743:21;106690:14;:75::i;:::-;106815:9;106810:94;106834:14;106830:1;:18;106810:94;;;106882:7;106890:1;106882:10;;;;;;;:::i;:::-;;;;;106870:6;106877:1;106870:9;;;;;;;:::i;:::-;;:22:::0;106850:3;::::1;::::0;::::1;:::i;:::-;;;;106810:94;;135412:336:::0;103449:10;-1:-1:-1;;;;;103463:7:0;103449:21;;103441:49;;;;-1:-1:-1;;;103441:49:0;;;;;;;:::i;:::-;135576:13:::1;:11;:13::i;:::-;135640:28;135656:4;135662:5;135640:15;:28::i;:::-;135679:27;135694:4;135700:5;135679:14;:27::i;:::-;135717:23;:6;135728:4:::0;135734:5;135717:10:::1;:23::i;:::-;135412:336:::0;;:::o;127514:206::-;127583:7;;127619:33;127583:7;127630:21;127619:10;:33::i;:::-;127603:49;;127670:42;127684:4;:27;;;127670:5;:13;;:42;;;;:::i;:::-;127663:49;127514:206;-1:-1:-1;;;127514:206:0:o;128630:569::-;128705:12;128737:62;128746:4;:25;;;128773:4;:25;;;128737:8;:62::i;:::-;128730:69;-1:-1:-1;128885:13:0;128901:33;128885:13;128912:21;128901:10;:33::i;:::-;128885:49;-1:-1:-1;128945:13:0;128961:33;128945:13;128972:21;128961:10;:33::i;:::-;128945:49;-1:-1:-1;129005:11:0;129027:19;128945:49;129039:6;129027:11;:19::i;:::-;129019:27;;:5;:27;:::i;:::-;129005:41;;102201:5;129065:3;:26;129057:57;;;;-1:-1:-1;;;129057:57:0;;;;;;;:::i;:::-;129134:38;129147:24;129159:11;:3;:9;:11::i;129147:24::-;129134:4;;:12;:38::i;128420:142::-;128501:7;128528:26;:8;128545;128528:16;:26::i;:::-;128521:33;;128420:142;;;;;:::o;127865:391::-;127933:7;;127980:44;127933:7;127991:32;127980:10;:44::i;:::-;127953:71;;128035:14;128079:16;101986:4;128053;:16;;;:22;;;;:::i;:::-;128052:43;;;;:::i;:::-;128035:60;-1:-1:-1;128106:13:0;128122:33;128106:13;128133:21;128122:10;:33::i;:::-;128106:49;-1:-1:-1;128173:75:0;128240:7;101986:4;128240:1;:7;:::i;:::-;128173:58;128224:6;128173:42;128187:4;:27;;;128173:5;:13;;:42;;;;:::i;:::-;:50;;:58::i;:75::-;128166:82;127865:391;-1:-1:-1;;;;;127865:391:0:o;102439:25::-;;;;;;;;;;;;;;;-1:-1:-1;102439:25:0;:::o;122942:2137::-;123087:7;;;123134:28;123149:13;123134:12;:28;:::i;:::-;123116:46;-1:-1:-1;123173:19:0;123195:28;123210:13;123195:12;:28;:::i;:::-;123173:50;-1:-1:-1;123234:19:0;123256:33;:13;123276:12;123256:19;:33::i;:::-;123234:55;-1:-1:-1;123391:12:0;;;:32;;-1:-1:-1;123407:16:0;;123391:32;123387:101;;;123448:12;123462:13;123440:36;;;;;;;;;123387:101;123633:21;;123715:11;123683:29;123633:21;;123683:10;:29::i;:::-;123679:33;;:1;:33;:::i;:::-;:47;;;;:::i;:::-;123665:61;;102201:5;123741:3;:26;123737:112;;;123800:24;123812:11;:3;:9;:11::i;123800:24::-;123784:40;;123737:112;124166:21;124190:28;:11;124210:7;124190:19;:28::i;:::-;124166:52;-1:-1:-1;124229:17:0;124268:120;124337:36;124359:13;;124337:21;:36::i;:::-;124331:42;;101986:4;124331:42;:::i;:::-;124268:36;124290:13;;124268:21;:36::i;:120::-;124249:139;;101986:4;124249:139;:::i;:::-;124229:159;-1:-1:-1;124477:43:0;124493:26;124511:7;124517:1;101986:4;124511:7;:::i;:::-;124493:9;;:17;:26::i;:::-;124477:7;;:15;:43::i;:::-;124467:53;-1:-1:-1;124676:34:0;:11;124696:13;124676:19;:34::i;:::-;124662:48;-1:-1:-1;124916:1:0;124891:21;124662:48;124891:7;:21;:::i;:::-;124890:27;;;;:::i;:::-;124875:42;-1:-1:-1;124932:17:0;;124928:97;;124982:31;:11;125000:12;124982:17;:31::i;:::-;124966:47;;124928:97;125043:12;125057:13;125035:36;;;;;;;;;;;122942:2137;;;;;;;:::o;121160:454::-;121194:18;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121194:18:0;121298:13;:11;:13::i;:::-;121430:23;121471:4;-1:-1:-1;;;;;121456:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121430:55;;121504:17;121516:4;121504:11;:17::i;:::-;121496:41;;;;-1:-1:-1;;;121496:41:0;;17250:2:1;121496:41:0;;;17232:21:1;17289:2;17269:18;;;17262:30;-1:-1:-1;;;17308:18:1;;;17301:41;17359:18;;121496:41:0;17048:335:1;121496:41:0;121602:4;121160:454;-1:-1:-1;121160:454:0:o;116856:4149::-;103617:10;;;;103616:11;103608:39;;;;-1:-1:-1;;;103608:39:0;;;;;;;:::i;:::-;116942:13:::1;::::0;;;;;;117225:32:::1;:9;117239:5:::0;117246:10;117225:13:::1;:32::i;:::-;117198:59;;117280:12;:3;:10;:12::i;:::-;117272:40;;;;-1:-1:-1::0;;;117272:40:0::1;;;;;;;:::i;:::-;117379:23;117405:8;:6;:8::i;:::-;117379:34;;117468:21;117492:3;:10;;;:29;;117514:7;;117492:29;;;117505:6;;117492:29;117468:53;;117536:27;117566:3;:10;;;:41;;117594:13;;117566:41;;;117579:12;;117566:41;117536:71:::0;-1:-1:-1;117622:17:0::1;117642:37;117622:17:::0;117653:25:::1;117642:10;:37::i;:::-;117622:57:::0;-1:-1:-1;101986:4:0::1;117977:18;117990:4:::0;117977:12:::1;:18::i;:::-;117969:26:::0;-1:-1:-1;118085:318:0::1;118124:13:::0;118160:19;117969:26;118230:9;118262:53:::1;:6;118273:41;118262:10;:53::i;:::-;118338:46;:6;118349:34;118338:10;:46::i;:::-;118085:3:::0;;:318;;;;;:16:::1;:318::i;:::-;118059:399;;;::::0;-1:-1:-1;;;118059:399:0;;19095:2:1;118059:399:0::1;::::0;::::1;19077:21:1::0;19134:2;19114:18;;;19107:30;-1:-1:-1;;;19153:18:1;;;19146:49;19212:18;;118059:399:0::1;18893:343:1::0;118059:399:0::1;118606:73;:3:::0;118616:8;118626:13;118641:19;118662:5;118669:9;118606::::1;:73::i;:::-;118598:81:::0;-1:-1:-1;118701:18:0::1;:3:::0;118710:8;118701::::1;:18::i;:::-;118694:25:::0;-1:-1:-1;118868:61:0::1;118882:46;:6;118893:34;118882:10;:46::i;:::-;118868:5:::0;;:13:::1;:61::i;:::-;118851:78:::0;-1:-1:-1;118962:22:0::1;118851:78:::0;118962:5;:22:::1;:::i;:::-;118944:40:::0;-1:-1:-1;119147:110:0::1;119189:53;:6;119200:41;119189:10;:53::i;119147:110::-;119132:125:::0;-1:-1:-1;119272:31:0::1;119132:125:::0;119272:31;::::1;:::i;:::-;;;119541:3;:10;;;119537:473;;;119581:116;119619:59;:3:::0;119633:8;119643:13;119658:19;119619:13:::1;:59::i;119581:116::-;119572:6;:125:::0;119732:29:::1;:3:::0;119752:8;119732:19:::1;:29::i;:::-;119716:12;;:45;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;119537:473:0::1;::::0;-1:-1:-1;119537:473:0::1;;119812:117;119851:59;:3:::0;119865:8;119875:13;119890:19;119851:13:::1;:59::i;119812:117::-;119802:7;:127:::0;119965:29:::1;:3:::0;119985:8;119965:19:::1;:29::i;:::-;119948:13;;:46;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;119537:473:0::1;120075:72;120133:12:::0;120095:28:::1;120118:4:::0;120102:5;120095:28:::1;:::i;:::-;:51;;;;:::i;120075:72::-;-1:-1:-1::0;120254:4:0::1;120237:14;::::0;::::1;:21:::0;;120273:12:::1;::::0;::::1;:16:::0;;;120304:21:::1;::::0;::::1;:25:::0;120344:37:::1;:9;120358:5:::0;120365:10;120237:3;120344:13:::1;:37::i;:::-;117145:3248;;;;;;120492:5;-1:-1:-1::0;;;;;120443:176:0::1;120467:10;-1:-1:-1::0;;;;;120443:176:0::1;;120512:10;120575:12;120560:4;120544:5;120537:28;;;;:::i;:::-;:51;;;;:::i;:::-;120443:176;::::0;;19441:25:1;;;19497:2;19482:18;;19475:34;;;;19525:18;;19518:34;;;19429:2;19414:18;120443:176:0::1;;;;;;;-1:-1:-1::0;;;;;120693:3:0::1;:8;;120717:12:::0;120702::::1;120709:5:::0;120702:4;:12:::1;:::i;:::-;:27;;;;:::i;:::-;120693:37;;;;;;;;;;;;;160:25:1::0;;148:2;133:18;;14:177;120693:37:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;120813:40:0::1;::::0;-1:-1:-1;;;120813:40:0;;120826:10:::1;120813:40;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;;;120813:3:0::1;-1:-1:-1::0;;;;;120813:12:0::1;::::0;-1:-1:-1;120813:12:0::1;::::0;-1:-1:-1;12210:18:1;;120813:40:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;120925:3;-1:-1:-1::0;;;;;120925:12:0::1;;120956:7;-1:-1:-1::0;;;;;120938:39:0::1;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;120925:72;::::0;-1:-1:-1;;;;;;120925:72:0::1;::::0;;;;;;-1:-1:-1;;;;;12255:32:1;;;120925:72:0::1;::::0;::::1;12237:51:1::0;12304:18;;;12297:34;;;12210:18;;120925:72:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;116931:4074;;;;;;116856:4149:::0;;:::o;125209:571::-;125485:48;;;;;;;;125519:14;125485:48;;;;;;;-1:-1:-1;;;125485:48:0;;;;;;;;-1:-1:-1;;;125485:48:0;;;;;;;;;;;;125283:7;;;;125575:48;;125283:7;;125586:36;;125575:10;:48;:::i;:::-;125544:79;-1:-1:-1;125645:60:0;:8;125664:15;125544:79;125703:1;125645:18;:60::i;:::-;125634:71;;125722:29;125737:8;125747:3;125722:14;:29::i;:::-;125716:35;125209:571;-1:-1:-1;;;;125209:571:0:o;126121:673::-;126239:7;126264:13;126287:21;:8;57421:16;;;57414:24;;;57323:123;126287:21;126264:45;-1:-1:-1;126320:32:0;126355:52;126320:32;126366:40;126355:10;:52::i;:::-;126320:87;;126439:24;126422:6;:42;126418:178;;126488:3;126481:10;;;;;;126418:178;126523:36;126534:24;126523:1;:36;:::i;:::-;126513:6;:46;126509:87;;126583:1;126576:8;;;;;;126509:87;126665:18;126696:49;126704:6;126720:24;126696:23;:49::i;:::-;126686:7;101986:4;126686:1;:7;:::i;:::-;:59;;;;:::i;:::-;126665:80;-1:-1:-1;126763:23:0;:3;126665:80;126763:11;:23::i;126922:472::-;127046:7;127075:4;:15;;;127071:295;;;127189:34;127198:3;127203:19;127217:4;127203:13;:19::i;:::-;127189:8;:34::i;:::-;127183:40;;127321:33;127330:3;127335:18;127348:4;127335:12;:18::i;127321:33::-;127315:39;;127071:295;-1:-1:-1;127383:3:0;126922:472;-1:-1:-1;126922:472:0:o;140848:89::-;103617:10;;;;103616:11;103608:39;;;;-1:-1:-1;;;103608:39:0;;;;;;;:::i;:::-;103449:10:::1;-1:-1:-1::0;;;;;103463:7:0::1;103449:21;;103441:49;;;;-1:-1:-1::0;;;103441:49:0::1;;;;;;;:::i;:::-;140912:10:::2;:17:::0;;-1:-1:-1;;140912:17:0::2;140925:4;140912:17;::::0;;140848:89::o;77828:107::-;77886:7;77918:1;77913;:6;;:14;;77926:1;77913:14;;;-1:-1:-1;77922:1:0;;77828:107;-1:-1:-1;77828:107:0:o;70579:133::-;70658:7;70685:4;70698;70690:13;;;;;;;;:::i;:::-;70685:19;;;;;;;:::i;:::-;;;;70579:133;-1:-1:-1;;;70579:133:0:o;45221:560::-;45281:7;;45319:5;45323:1;45319;:5;:::i;:::-;45301:23;-1:-1:-1;45339:12:0;45335:439;;45375:1;45368:8;;;;;45335:439;44063:4;45739:11;45749:1;45739:7;:11;:::i;:::-;45738:19;;;;:::i;:::-;45737:25;;45761:1;45737:25;:::i;:::-;45730:32;;;;;49896:394;49945:7;49969:6;49965:49;;-1:-1:-1;44063:4:0;;49896:394;-1:-1:-1;49896:394:0:o;49965:49::-;-1:-1:-1;;;50032:1:0;:10;50024:50;;;;-1:-1:-1;;;50024:50:0;;20323:2:1;50024:50:0;;;20305:21:1;20362:2;20342:18;;;20335:30;20401:29;20381:18;;;20374:57;20448:18;;50024:50:0;20121:351:1;50024:50:0;50112:1;50087:15;50147:24;50112:1;50147:14;:24::i;:::-;50125:47;;50183:16;50202:42;50206:34;50212:3;44239:5;50206;:34::i;:::-;50242:1;50202:3;:42::i;:::-;50183:61;;50264:18;50268:3;50273:8;50264:3;:18::i;6534:277::-;6595:6;;6632:16;6182:3;6115:4;6632:16;:::i;:::-;6614:34;-1:-1:-1;6659:14:0;6676:15;6614:34;6676:5;:15;:::i;:::-;6659:32;-1:-1:-1;6720:16:0;6710:26;;;6702:69;;;;-1:-1:-1;;;6702:69:0;;20679:2:1;6702:69:0;;;20661:21:1;20718:2;20698:18;;;20691:30;20757:32;20737:18;;;20730:60;20807:18;;6702:69:0;20477:354:1;6284:173:0;6345:7;;6386:16;6182:3;6115:4;6386:16;:::i;:::-;6365:37;-1:-1:-1;6421:27:0;6365:37;6421:14;;;:27;:::i;87766:234::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87963:27:0;;21009:15:1;;;;-1:-1:-1;;21005:53:1;87963:27:0;;;20993:66:1;21075:12;;;;21068:28;;;;87963:27:0;;;;;;;;;;21112:12:1;;;87963:27:0;;;87953:38;;;;;;;;;87948:44;;;;;;;;;87936:56;;;;;;;;-1:-1:-1;;;;;87936:56:0;;;;;-1:-1:-1;;;87936:56:0;;;;;;;-1:-1:-1;;;87936:56:0;;;;;;;;;;-1:-1:-1;;;87936:56:0;;;;;;;;-1:-1:-1;;;87936:56:0;;;;;;;;;;;;;-1:-1:-1;;;87936:56:0;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;87936:56:0;;;;;;;;;;;;;;;;;21112:12:1;87766:234:0:o;89688:145::-;89745:12;89779:4;:15;;;89778:16;:46;;;;-1:-1:-1;;89798:22:0;;;:26;;;;;89688:145::o;129989:175::-;130058:12;130090:66;130103:4;:25;;;130130:4;:25;;;130090:12;:66::i;100375:1059::-;100664:9;86748:4;100664:9;100748:31;100764:4;86748;100748:15;:31::i;:::-;100719:60;;100796:4;:15;;;:46;;;-1:-1:-1;100815:22:0;;;;:27;;;100796:46;100792:222;;;100997:5;100990:12;;;;;;100792:222;101026:11;101040:171;101060:4;101079:8;101102:13;101130:19;101164:12;101191:9;101040:5;:171::i;:::-;101026:185;-1:-1:-1;101222:25:0;101250:51;:18;101275:25;101250:24;:51::i;:::-;101222:79;-1:-1:-1;101312:22:0;101337:31;:3;101349:18;101337:11;:31::i;:::-;101312:56;-1:-1:-1;101392:34:0;101312:56;101392:17;:34;:::i;:::-;101386:40;;;;100375:1059;-1:-1:-1;;;;;;;;;;;;100375:1059:0:o;95534:418::-;95707:7;95727:16;95746:31;95762:4;95768:8;95746:15;:31::i;:::-;95727:50;-1:-1:-1;95792:13:0;;;:35;;-1:-1:-1;95809:18:0;;95792:35;:63;;;-1:-1:-1;95831:24:0;;95792:63;95788:77;;;95864:1;95857:8;;;;;95788:77;95883:61;95899:8;95909:13;95924:19;95883:15;:61::i;131166:694::-;131364:51;;;;;;;;131398:17;131364:51;;;;;;;-1:-1:-1;;;131364:51:0;;;;;;;;-1:-1:-1;;;131364:51:0;;;;;;;;;;;;131299:7;;;;131448:17;;:6;;131461:3;;131448:12;:17;:::i;:::-;131653:16;;;;131426:40;;-1:-1:-1;131617:60:0;;:8;;131636:15;;131426:40;131617:18;:60::i;:::-;131733:28;;:17;:28;;;;;;;;;;;;;;-1:-1:-1;;131733:28:0;;;;;;;-1:-1:-1;;;131733:28:0;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;131733:28:0;;;;;;;;-1:-1:-1;57414:24:0;;131815:37;131166:694;-1:-1:-1;;;;;;131166:694:0:o;130318:::-;130516:51;;;;;;;;130550:17;130516:51;;;;;;;-1:-1:-1;;;130516:51:0;;;;;;;;-1:-1:-1;;;130516:51:0;;;;;;;;;;;;130451:7;;;;130600:17;;:6;;130613:3;;130600:12;:17;:::i;:::-;130805:16;;;;130578:40;;-1:-1:-1;130769:60:0;;:8;;130788:15;;130578:40;130769:18;:60::i;:::-;130885:28;;:17;:28;;;;;;;;;;;;;;-1:-1:-1;;130885:28:0;;;;;;;-1:-1:-1;;;130885:28:0;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;130885:28:0;;;;;;;;-1:-1:-1;57414:24:0;;130982:21;57323:123;96776:2009;97004:12;97029:20;97052:25;97062:4;97068:8;97052:9;:25::i;:::-;97029:48;;97088:26;97117:31;97133:4;97139:8;97117:15;:31::i;:::-;97088:60;;97159:15;97177:27;97189:4;97195:8;97177:11;:27::i;:::-;97159:45;;97217:20;97240:61;97250:4;97256:8;97266:13;97281:19;97240:9;:61::i;:::-;97217:84;;97312:21;97336:16;97347:4;97336:10;:16::i;:::-;97312:40;;97683:4;:11;;;97679:1099;;;98013:161;98044:32;:12;98063;98044:18;:32::i;:::-;98099:56;98139:15;98145:9;86748:4;98139:15;:::i;:::-;98099:33;:12;98118:13;98099:18;:33::i;:::-;:39;;:56::i;98013:161::-;97935:58;97980:12;97935:38;:18;97960:12;97935:24;:38::i;:::-;:44;;:58::i;:::-;:239;;;;:::i;:::-;97911:263;-1:-1:-1;98223:58:0;98247:33;:12;98266:13;98247:18;:33::i;:::-;98237:43;;:7;:43;:::i;:::-;98223:4;;:13;:58::i;:::-;98216:65;;97679:1099;;;98627:33;:12;98646:13;98627:18;:33::i;:::-;98549:58;98594:12;98549:38;:18;98574:12;98549:24;:38::i;:58::-;:111;;;;:::i;:::-;98525:135;-1:-1:-1;98709:57:0;98733:32;:12;98752;98733:18;:32::i;98709:57::-;98702:64;;97679:1099;97018:1767;;;;;96776:2009;;;;;;;;:::o;96032:408::-;96105:7;96125:26;96154:31;96170:4;96176:8;96154:15;:31::i;:::-;96125:60;;96196:15;96214:27;96226:4;96232:8;96214:11;:27::i;:::-;96196:45;-1:-1:-1;96343:18:0;96382:25;96343:18;96196:45;96382:16;:25::i;99617:567::-;99883:19;99915;99937:181;99967:4;99986:8;100009:13;100037:19;100071:12;100098:9;99937:15;:181::i;:::-;99915:203;-1:-1:-1;100143:33:0;99915:203;100161:14;100143:17;:33::i;:::-;100129:47;99617:567;-1:-1:-1;;;;;;;;;99617:567:0:o;78011:106::-;78069:7;78100:1;78096;:5;:13;;78108:1;78096:13;;44922:139;44985:7;45005:9;45021:1;45017;:5;:17;;45033:1;45017:17;;;45025:5;45029:1;45025;:5;:::i;94457:281::-;94541:7;94561:28;94592:15;94602:4;89106:13;;;-1:-1:-1;;;;;89098:22:0;;89012:116;94592:15;94561:46;-1:-1:-1;94692:38:0;94561:46;94721:8;94692:28;:38::i;132011:693::-;132135:48;;;;;;;;132169:14;132135:48;;;;;;;-1:-1:-1;;;132135:48:0;;;;;;;;-1:-1:-1;;;132135:48:0;;;;;;;;;;;;132071:6;;;;132361:48;;132071:6;;132372:36;;132361:10;:48;:::i;:::-;132330:79;-1:-1:-1;132431:64:0;:8;132450:15;132330:79;132489:5;132431:18;:64::i;:::-;132551:25;;:14;:25;;;;;;;;;;;;;;-1:-1:-1;;132551:25:0;;;;;;;-1:-1:-1;;;132551:25:0;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;132551:25:0;;;;;;;;-1:-1:-1;;;57414:24:0;;132651:21;57323:123;90417:357;90544:6;86748:4;90576:15;:22;;90568:53;;;;-1:-1:-1;;;90568:53:0;;9848:2:1;90568:53:0;;;9830:21:1;9887:2;9867:18;;;9860:30;-1:-1:-1;;;9906:18:1;;;9899:48;9964:18;;90568:53:0;9646:342:1;90568:53:0;90632:25;90660:55;90693:21;90699:15;86748:4;90693:21;:::i;:::-;90660:24;90679:4;90660:18;:24::i;:55::-;90632:83;;90733:33;:17;:31;:33::i;88064:227::-;88243:27;;-1:-1:-1;;21013:2:1;21009:15;;;21005:53;88243:27:0;;;20993:66:1;21075:12;;;21068:28;;;88275:8:0;;88228:4;;:44;;21112:12:1;;88243:27:0;;;;;;-1:-1:-1;;88243:27:0;;;;;;88233:38;;88243:27;88233:38;;;;88228:44;;;;;;;;;;;;-1:-1:-1;88228:44:0;:55;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;88228:55:0;;;-1:-1:-1;;;;;;88228:55:0;;;;;;;-1:-1:-1;;;88228:55:0;;;;;;;;;;;;-1:-1:-1;;;;88228:55:0;-1:-1:-1;;;88228:55:0;;;;;-1:-1:-1;;;;88228:55:0;;-1:-1:-1;;;88228:55:0;;;;;;;;;-1:-1:-1;;;;;88228:55:0;;;-1:-1:-1;;;88228:55:0;;;;;-1:-1:-1;;;;;88228:55:0;;-1:-1:-1;;;88228:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;88228:55:0;;;;-1:-1:-1;;;;88064:227:0:o;45789:231::-;45851:7;45875:6;45871:142;;-1:-1:-1;45905:1:0;45898:8;;45871:142;45939:17;45959:7;44063:4;45959:1;:7;:::i;:::-;45939:27;-1:-1:-1;45988:13:0;46000:1;45939:27;45988:13;:::i;46028:562::-;46088:7;46112:6;46108:475;;-1:-1:-1;46142:1:0;46135:8;;46108:475;46176:17;46196:7;44063:4;46196:1;:7;:::i;:::-;46176:27;-1:-1:-1;46565:1:0;46548:13;46560:1;46176:27;46548:13;:::i;134009:1195::-;134128:17;134192:21;134216:6;:25;;134234:7;;134216:25;;;134225:6;;134216:25;134192:49;;134252:27;134282:6;:37;;134306:13;;134282:37;;;134291:12;;134282:37;134252:67;;134364:16;134383:61;134405:2;134409:13;134424:19;134383:21;:61::i;:::-;134364:80;-1:-1:-1;134515:19:0;134532:2;134515:19;;:::i;:::-;;-1:-1:-1;134545:31:0;134568:8;134545:31;;:::i;:::-;;;134697:22;134722:37;134753:5;134722:30;:37::i;:::-;134697:62;;134795:14;134778:13;:31;;134770:56;;;;-1:-1:-1;;;134770:56:0;;21337:2:1;134770:56:0;;;21319:21:1;21376:2;21356:18;;;21349:30;-1:-1:-1;;;21395:18:1;;;21388:42;21447:18;;134770:56:0;21135:336:1;134770:56:0;134908:6;134904:216;;;134931:6;:22;;;134968:12;:34;;;134904:216;;;135035:7;:23;;;135073:13;:35;;;134904:216;-1:-1:-1;135188:8:0;134009:1195;-1:-1:-1;;;;;;134009:1195:0:o;55511:382::-;55570:5;;55605:25;:5;55051:9;55605:13;:25::i;:::-;55588:42;;-1:-1:-1;;55649:7:0;:23;;:50;;;;;55107:6;55676:7;:23;;55649:50;55641:88;;;;-1:-1:-1;;;55641:88:0;;21678:2:1;55641:88:0;;;21660:21:1;21717:2;21697:18;;;21690:30;-1:-1:-1;;;21736:18:1;;;21729:55;21801:18;;55641:88:0;21476:349:1;55641:88:0;55863:21;55001:4;55863:7;:21;:::i;140184:501::-;140384:36;140376:4;:44;;;;;;;;:::i;:::-;;140372:306;;;140437:23;140478:4;-1:-1:-1;;;;;140463:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;140597:16;;;;140437:55;;-1:-1:-1;140539:5:0;;140507:29;;140573:40;;140539:5;140573:40;:::i;:::-;140559:54;;140643:11;:3;:9;:11::i;:::-;140628:12;:26;-1:-1:-1;;;140184:501:0;;:::o;132845:917::-;132946:19;132986;;132968:15;:37;;;;:::i;:::-;132946:59;-1:-1:-1;133020:15:0;;133016:739;;133144:7;;133135:6;;:16;133111:21;133135:16;133189:35;;133217:7;;133189:35;;;133208:6;;133189:35;133166:58;;133239:21;133263:16;:35;;133292:6;;133263:35;;;133282:7;;133263:35;133239:59;;133345:122;133378:12;133409:13;133441:11;133345:14;:122::i;:::-;133313:154;;-1:-1:-1;133313:154:0;-1:-1:-1;133521:16:0;:47;;133555:13;133521:47;;;133540:12;133521:47;133512:6;:56;133593:16;:47;;133628:12;133593:47;;;133612:13;133593:47;133583:7;:57;-1:-1:-1;;133728:15:0;133706:19;:37;-1:-1:-1;133016:739:0;132876:886;132845:917::o;135830:4241::-;136181:21;136173:4;:29;;;;;;;;:::i;:::-;;136169:671;;;136236:5;136219:14;136278:39;136219:14;136289:27;136278:10;:39::i;:::-;136256:61;-1:-1:-1;136332:33:0;136368:85;136332:33;136397:41;136368:10;:85::i;:::-;136332:121;-1:-1:-1;136468:26:0;136497:46;136468:26;136508:34;136497:10;:46::i;:::-;136468:75;-1:-1:-1;136620:133:0;136671:59;136705:24;136468:75;101986:4;136705:24;:::i;136671:59::-;136658:10;136662:6;136658:1;:10;:::i;136620:133::-;136584:11;:169;;136558:270;;;;-1:-1:-1;;;136558:270:0;;;;;;;:::i;:::-;136204:636;;;;136169:671;137116:27;137108:4;:35;;;;;;;;:::i;:::-;;137104:671;;;137183:5;137160:20;137219:33;137160:20;137230:21;137219:10;:33::i;:::-;137203:49;-1:-1:-1;137267:33:0;137303:85;137267:33;137332:41;137303:10;:85::i;:::-;137267:121;-1:-1:-1;137403:26:0;137432:46;137403:26;137443:34;137432:10;:46::i;:::-;137403:75;-1:-1:-1;137556:132:0;137606:59;137640:24;137403:75;101986:4;137640:24;:::i;137556:132::-;137519:12;:169;;137493:270;;;;-1:-1:-1;;;137493:270:0;;;;;;;:::i;:::-;137145:630;;;;137104:671;138036:41;138028:4;:49;;;;;;;;:::i;:::-;;138024:639;;;138131:5;138094:34;138167:33;138094:34;138178:21;138167:10;:33::i;:::-;138151:49;-1:-1:-1;138215:19:0;138237:39;138215:19;138248:27;138237:10;:39::i;:::-;138215:61;-1:-1:-1;138291:26:0;138320:46;138291:26;138331:34;138320:10;:46::i;:::-;138291:75;-1:-1:-1;138443:133:0;138493:60;138528:24;138291:75;101986:4;138528:24;:::i;:::-;138493:26;;:34;:60::i;138443:133::-;138407:11;:169;;138381:270;;;;-1:-1:-1;;;138381:270:0;;;;;;;:::i;:::-;138079:584;;;;138024:639;138931:34;138923:4;:42;;;;;;;;:::i;:::-;;138919:671;;;139012:5;138982:27;139048:33;138982:27;139059:21;139048:10;:33::i;:::-;139032:49;-1:-1:-1;139096:19:0;139118:39;139096:19;139129:27;139118:10;:39::i;:::-;139096:61;-1:-1:-1;139172:33:0;139208:85;139172:33;139237:41;139208:10;:85::i;:::-;139172:121;-1:-1:-1;139370:133:0;139420:60;139454:25;139460:19;101986:4;139454:25;:::i;:::-;139420;;:33;:60::i;139370:133::-;139334:11;:169;;139308:270;;;;-1:-1:-1;;;139308:270:0;;;;;;;:::i;:::-;138967:623;;;;138919:671;139718:36;139710:4;:44;;;;;;;;:::i;:::-;;139706:358;;;139771:23;139812:4;-1:-1:-1;;;;;139797:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;139943:16;;;;139771:55;;-1:-1:-1;139873:5:0;;102201;;139919:40;;139873:5;139919:40;:::i;:::-;:63;139893:159;;;;-1:-1:-1;;;139893:159:0;;;;;;;:::i;:::-;139756:308;;135830:4241;;:::o;70793:160::-;70940:5;70918:4;70931;70923:13;;;;;;;;:::i;:::-;70918:19;;;;;;;:::i;:::-;;:27;-1:-1:-1;;;70793:160:0:o;45069:144::-;45131:7;;45169:5;45173:1;45169;:5;:::i;:::-;45151:23;-1:-1:-1;45192:13:0;44063:4;45151:23;45192:13;:::i;46836:945::-;46898:7;47131:6;;;:18;;;44063:4;47141:1;:8;47131:18;47127:647;;;-1:-1:-1;44063:4:0;47166:10;;47127:647;47198:6;47194:580;;-1:-1:-1;47228:1:0;47221:8;;47194:580;44063:4;47251:1;:8;47247:527;;;-1:-1:-1;47283:1:0;47276:8;;47247:527;44127:7;44063:4;44127:1;:7;:::i;:::-;47306:1;:8;47302:472;;;47338:13;47346:1;47349;47338:7;:13::i;:::-;47331:20;;;;47302:472;44174:7;44063:4;44174:1;:7;:::i;:::-;47373:1;:9;47369:405;;;47399:14;47416:13;47424:1;47427;47416:7;:13::i;:::-;47399:30;;47451:23;47459:6;47467;47451:7;:23::i;47369:405::-;47507:11;47521:20;47536:1;47539;47521:14;:20::i;:::-;47507:34;;47556:16;47575:42;47579:34;47585:3;44239:5;47579;:34::i;47575:42::-;47556:61;;47644:8;47638:3;:14;47634:129;;;47680:1;47673:8;;;;;;47634:129;47729:18;47733:3;47738:8;47729:3;:18::i;:::-;47722:25;;;;;;57588:2425;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;57930:14:0;;-1:-1:-1;;57800:9:0;;57915:29;;;;;;;;;:161;;58061:14;;58053:23;;;;;58013:37;;58030:20;;-1:-1:-1;;;58013:37:0;:::i;:::-;:63;;;;:::i;:::-;57915:161;;;57982:14;;57968:28;;:11;:28;:::i;:::-;57960:37;;57915:161;58116:11;;;;57902:174;;-1:-1:-1;58108:20:0;;58087:18;58164:16;58116:4;57421:16;;;57414:24;;;57323:123;58164:16;58139:41;;58203:10;58197:2;:16;;:35;;;-1:-1:-1;58217:15:0;;58197:35;58193:354;;;58347:188;;;;;;;;58390:11;58347:188;;;;;;58432:24;:6;:22;:24::i;:::-;58347:188;;;;;;58492:23;:5;:21;:23::i;:::-;58347:188;;;;;58323:212;;;;;;;;58193:354;58868:10;58841:15;58854:2;58868:10;58841:15;:::i;:::-;58816:41;;:15;:41;:::i;:::-;58815:64;;;;:::i;:::-;58797:82;-1:-1:-1;58945:21:0;58969:23;58987:5;58797:82;58969:23;:::i;:::-;58945:47;-1:-1:-1;59007:19:0;59003:313;;59138:166;;;;;;;;59181:11;59138:166;;;;;;59223:24;:6;:22;:24::i;:::-;59138:166;;;;59283:1;59138:166;;;;;59114:190;-1:-1:-1;59114:190:0;;-1:-1:-1;;;;;59114:190:0;59003:313;59640:10;59653:21;:15;:19;:21::i;:::-;59640:34;;59685:10;59698:11;:5;:9;:11::i;:::-;59685:24;-1:-1:-1;59720:17:0;59782:7;59685:24;59782:2;:7;:::i;:::-;59766:11;59771:6;59766:2;:11;:::i;:::-;59747:15;59760:2;59747:10;:15;:::i;:::-;59741:22;;:2;:22;:::i;:::-;:36;;;;:::i;:::-;59740:50;;;;:::i;:::-;59720:70;;59821:184;;;;;;;;59860:11;59821:184;;;;;;59898:27;:9;:25;:27::i;:::-;59821:184;;;;;;59957:32;:14;:30;:32::i;:::-;59821:184;;;;59801:204;57588:2425;-1:-1:-1;;;;;;;;;;;;;57588:2425:0:o;27580:5970::-;27626:6;27645:89;-1:-1:-1;;27654:1:0;:25;;:54;;;;;22694:6;27683:1;:25;;27654:54;11770:1;27645:8;:89::i;:::-;27780:1;27776;:5;27772:378;;;28126:7;28131:1;28130:2;;28126:3;:7::i;:::-;-1:-1:-1;;;28106:27:0;;;;;:::i;:::-;;;27580:5970;-1:-1:-1;;27580:5970:0:o;27772:378::-;29530:14;23143:21;29563:1;:7;29559:260;;-1:-1:-1;;;29591:7:0;;;;23200:56;29559:260;;;23309:20;29655:1;:7;29651:168;;-1:-1:-1;;;29683:7:0;;;;23365:28;29651:168;;;-1:-1:-1;29772:1:0;29651:168;29990:3;29985:8;;;;;22089:4;23477:22;30266:7;;30262:107;;-1:-1:-1;;30294:7:0;;;;22089:4;23535:34;30331:12;;30330:23;30320:33;;30262:107;23608:22;30387:1;:7;30383:107;;-1:-1:-1;;30415:7:0;;;;22089:4;23666:27;30452:12;;30451:23;30441:33;;30383:107;23732:21;30508:1;:7;30504:107;;-1:-1:-1;;30536:7:0;;;;22089:4;23789:24;30573:12;;30572:23;30562:33;;30504:107;23852:21;30629:1;:7;30625:107;;-1:-1:-1;;30657:7:0;;;;22089:4;23909:22;30694:12;;30693:23;30683:33;;30625:107;23970:21;30750:1;:7;30746:107;;-1:-1:-1;;30778:7:0;;;;22089:4;24027:21;30815:12;;30814:23;30804:33;;30746:107;24087:21;30871:1;:7;30867:107;;-1:-1:-1;;30899:7:0;;;;24087:21;24144;30936:12;;30935:23;30925:33;;30867:107;24204:20;30992:1;:7;30988:107;;-1:-1:-1;;31020:7:0;;;;22089:4;24261:21;31057:12;;31056:23;31046:33;;30988:107;24321:20;31113:1;:7;31109:107;;-1:-1:-1;;31141:7:0;;;;22089:4;24378:21;31178:12;;31177:23;31167:33;;31109:107;22089:4;31792:17;;;;;;32094:1;;32072:8;;;32071:19;32070:25;32110:17;;;;32070:25;-1:-1:-1;32175:1:0;22089:4;32153:8;;;32152:19;32151:25;32191:17;;;;32151:25;-1:-1:-1;32256:1:0;22089:4;32234:8;;;32233:19;32232:25;32272:17;;;;32232:25;-1:-1:-1;32337:1:0;22089:4;32315:8;;;32314:19;32313:25;32353:17;;;;32313:25;-1:-1:-1;32418:1:0;22089:4;32396:8;;;32395:19;32394:25;32434:17;;;;32394:25;-1:-1:-1;32499:1:0;22089:4;32477:8;;;32476:19;32475:25;32515:17;;;;32475:25;-1:-1:-1;32580:1:0;22089:4;32558:8;;;32557:19;32556:25;32596:17;;;;32556:25;-1:-1:-1;32661:1:0;22089:4;32639:8;;;32638:19;32637:25;32677:17;;;;32637:25;-1:-1:-1;32742:2:0;22089:4;32720:8;;;32719:19;32718:26;32759:17;;;;32718:26;-1:-1:-1;32824:2:0;22089:4;32802:8;;;32801:19;32800:26;32841:17;;;;32800:26;-1:-1:-1;32906:2:0;22089:4;32884:8;;;32883:19;32882:26;32923:17;;;;32882:26;-1:-1:-1;33528:3:0;22089:4;33484:19;;;33483:30;33482:42;;33481:50;;27580:5970;-1:-1:-1;;;;;;27580:5970:0:o;44426:195::-;44484:7;;44589:5;44593:1;44589;:5;:::i;78236:156::-;78298:7;78373:11;78383:1;78374:5;;;78373:11;:::i;:::-;78363:21;;78364:5;;;78363:21;:::i;93433:307::-;93517:7;93537:25;93565:24;93584:4;93565:18;:24::i;:::-;93537:52;;93600:28;93631:47;93660:17;93631:22;93648:4;88669:20;-1:-1:-1;;;;;88661:29:0;;88568:130;93631:47;93600:78;-1:-1:-1;93696:36:0;93600:78;93723:8;93696:26;:36::i;1016:4221::-;1132:14;;;-1:-1:-1;;1705:1:0;1702;1695:20;1749:1;1746;1742:9;1733:18;;1805:5;1801:2;1798:13;1790:5;1786:2;1782:14;1778:34;1769:43;;;1910:5;1919:1;1910:10;1906:209;;;1963:1;1949:11;:15;1941:24;;;;;;-1:-1:-1;2026:23:0;;;;-1:-1:-1;2086:13:0;;1906:209;2258:5;2244:11;:19;2236:28;;;;;;2573:17;2659:11;2656:1;2653;2646:25;3062:12;3078:15;;;3077:31;;3217:22;;;;;4112:1;4093;:15;;4092:21;;4359:17;;;4355:21;;4348:28;4422:17;;;4418:21;;4411:28;4486:17;;;4482:21;;4475:28;4550:17;;;4546:21;;4539:28;4614:17;;;4610:21;;4603:28;4679:17;;;4675:21;;;4668:28;3640:12;;;;3636:23;;;3661:1;3632:31;2808:20;;;2797:32;;;3701:12;;;;2856:21;;;;3366:16;;;;3692:21;;;;5179:11;;;;;-1:-1:-1;;1016:4221:0;;;;;:::o;93946:297::-;94024:7;94044:25;94072:24;94091:4;94072:18;:24::i;:::-;94044:52;;94107:29;94139:41;94162:17;94139:16;94150:4;94139:10;:16::i;94927:291::-;95007:7;95027:25;95055:24;95074:4;95055:18;:24::i;:::-;95027:52;;95090:24;95117:43;95142:17;95117:18;95130:4;88873:16;;;-1:-1:-1;;;;;88865:25:0;;88776:122;91688:147;91749:19;91795:32;91812:4;:14;;;91795:16;:32::i;98919:577::-;99157:24;99194:16;99213:171;99233:4;99252:8;99275:13;99303:19;99337:12;99364:9;99213:5;:171::i;:::-;99194:190;;99395:15;99413:27;99425:4;99431:8;99413:11;:27::i;:::-;99395:45;-1:-1:-1;99470:18:0;99395:45;99470:8;:18;:::i;89217:142::-;89285:7;89312:39;:4;:22;;;:37;;;:39::i;92172:330::-;92315:17;92358:18;;;:46;;-1:-1:-1;92380:24:0;;92358:46;92357:137;;92439:55;92455:2;92459:19;92480:13;92439:15;:55::i;:::-;92357:137;;;-1:-1:-1;92421:2:0;;92345:149;-1:-1:-1;;92172:330:0:o;50577:640::-;50639:6;50670:1;50666;:5;:19;;;;;-1:-1:-1;;;50675:1:0;:10;50666:19;50658:59;;;;-1:-1:-1;;;50658:59:0;;22726:2:1;50658:59:0;;;22708:21:1;22765:2;22745:18;;;22738:30;22804:29;22784:18;;;22777:57;22851:18;;50658:59:0;22524:351:1;50658:59:0;50740:1;50736;:5;:19;;;;;-1:-1:-1;;;50745:1:0;:10;50736:19;50728:59;;;;-1:-1:-1;;;50728:59:0;;23082:2:1;50728:59:0;;;23064:21:1;23121:2;23101:18;;;23094:30;23160:29;23140:18;;;23133:57;23207:18;;50728:59:0;22880:351:1;50728:59:0;50820:1;50854;50800:10;50880:25;50820:1;50854;50880:14;:25::i;:::-;50867:38;;50994:14;51068:1;51061:3;:8;;:21;;51079:3;51078:4;;51061:21;;;51072:3;51061:21;51044:39;;51105:16;51124:45;51128:37;51134:6;44239:5;51128;:37::i;51124:45::-;51105:64;-1:-1:-1;51187:22:0;51105:64;51187:3;:22;:::i;:::-;51180:29;50577:640;-1:-1:-1;;;;;;;;50577:640:0:o;24882:2477::-;24940:7;24989:6;24985:146;;-1:-1:-1;21895:4:0;25093:22;;24985:146;25151:6;25147:55;;-1:-1:-1;25185:1:0;25178:8;;25147:55;25599:44;-1:-1:-1;;;25608:1:0;:10;11607:1;25599:8;:44::i;:::-;25683:1;26061:57;23060:24;26070:23;;11659:1;26061:8;:57::i;:::-;26158:1;26133:15;22943:13;26215:28;-1:-1:-1;26215:60:0;;;;-1:-1:-1;22999:13:0;26247:28;;26215:60;26211:793;;;26296:14;26313:16;26320:8;26313:6;:16::i;:::-;26296:33;-1:-1:-1;21895:4:0;26848:16;;;26847:29;;26846:61;26814:8;21895:4;26773:7;:16;26772:50;:135;26756:152;;26277:647;26211:793;;;26980:8;26964:13;26968:8;26964:3;:13::i;:::-;:24;26949:39;;26211:793;21895:4;27018:22;;27125:165;-1:-1:-1;;27152:36:0;-1:-1:-1;27152:36:0;;;:76;;;22694:6;27192:12;:36;;27152:76;11717:1;27125:8;:165::i;:::-;27322:17;27326:12;27322:3;:17::i;44629:195::-;44687:7;;44792:5;44796:1;44792;:5;:::i;52815:194::-;52878:6;;52924:16;52915:25;;;52914:62;;52960:16;52914:62;;53139:266;53201:6;;-1:-1:-1;;;;;;53238:24:0;;:133;;-1:-1:-1;;;;;53311:24:0;;:59;;53364:5;53238:133;;53311:59;-1:-1:-1;;;;;53238:133:0;;;-1:-1:-1;;;;;;53220:151:0;53139:266;-1:-1:-1;;;53139:266:0:o;54527:218::-;54573:7;54715:1;54710;:6;;:15;;54724:1;54723:2;;54710:15;;;-1:-1:-1;54719:1:0;54527:218::o;7753:103::-;7823:9;7818:34;;7834:18;7842:9;7834:7;:18::i;92835:200::-;92895:7;92915:9;92927:22;92944:4;88669:20;-1:-1:-1;;;;;88661:29:0;;88568:130;92927:22;92915:34;;92960:11;92974:21;92990:4;92974:15;:21::i;:::-;92960:35;-1:-1:-1;93013:14:0;:1;92960:35;93013:9;:14::i;56237:484::-;56293:7;;56444:26;55001:4;56444:12;;;;:26;:::i;:::-;56427:43;;-1:-1:-1;;56489:7:0;:23;;:50;;;;;55107:6;56516:7;:23;;56489:50;56481:88;;;;-1:-1:-1;;;56481:88:0;;21678:2:1;56481:88:0;;;21660:21:1;21717:2;21697:18;;;21690:30;-1:-1:-1;;;21736:18:1;;;21729:55;21801:18;;56481:88:0;21476:349:1;56481:88:0;56582:11;56604:13;:7;:11;:13::i;:::-;56582:36;;56648:1;56637:7;:12;;:75;;56678:34;56690:21;55051:9;56707:3;56690:16;:21::i;56637:75::-;56652:23;55051:9;56671:3;56652:18;:23::i;33670:940::-;33731:6;;22943:13;34041:24;-1:-1:-1;34041:52:0;;;;-1:-1:-1;22999:13:0;34069:24;;34041:52;34037:184;;;34124:12;34131:4;34124:6;:12::i;:::-;34114:22;;34037:184;;;21895:4;34187:9;34191:4;34187:3;:9::i;:::-;:18;34177:28;;34037:184;34237:13;22943;34269:23;-1:-1:-1;34269:50:0;;;;-1:-1:-1;22999:13:0;34296:23;;34269:50;34265:178;;;34349:11;34356:3;34349:6;:11::i;:::-;34340:20;;34265:178;;;21895:4;34410:8;34414:3;34410;:8::i;:::-;:17;34401:26;;34265:178;34584:7;21895:4;34565:6;:15;34564:27;;;;;:::i;:::-;;;33670:940;-1:-1:-1;;;;;33670:940:0:o;41051:1921::-;21895:4;41363:11;41099:6;;-1:-1:-1;;;41800:10:0;;;;-1:-1:-1;;41775:10:0;;41774:21;41800:10;41773:38;;;;:::i;:::-;;;-1:-1:-1;41826:16:0;-1:-1:-1;;;41846:5:0;;;41845:16;;-1:-1:-1;41966:1:0;;-1:-1:-1;;;42203:15:0;;;42202:26;;-1:-1:-1;42262:1:0;42202:26;42256:7;42243:20;-1:-1:-1;;;42287:15:0;;;42286:26;;-1:-1:-1;42346:1:0;42286:26;42340:7;42327:20;-1:-1:-1;;;42371:15:0;;;42370:26;;-1:-1:-1;42430:1:0;42370:26;42424:7;42411:20;-1:-1:-1;;;42455:15:0;;;42454:26;;-1:-1:-1;42514:1:0;42454:26;42508:7;42495:20;-1:-1:-1;;;42539:15:0;;;42538:26;;-1:-1:-1;42598:2:0;42538:26;42592:8;42579:21;-1:-1:-1;;;42624:15:0;;;42623:26;;-1:-1:-1;42683:2:0;42623:26;42677:8;42664:21;-1:-1:-1;;;42709:15:0;;;42708:26;;-1:-1:-1;42768:2:0;42708:26;42762:8;42749:21;42952:1;42940:13;;;-1:-1:-1;;;;;41051:1921:0:o;35246:5531::-;35291:6;21895:4;35339:1;:10;35335:407;;;35699:26;35723:1;-1:-1:-1;;;35723:1:0;35703:21;;;;:::i;:::-;;35699:3;:26::i;:::-;35698:27;;;35246:5531;-1:-1:-1;;35246:5531:0:o;35335:407::-;37140:10;37178:11;37173:16;;37169:129;;23200:56;37210:7;;;-1:-1:-1;23143:21:0;37273:9;37169:129;37323:11;37318:16;;37314:129;;23365:28;37355:7;;;-1:-1:-1;23309:20:0;37418:9;37314:129;37592:3;37610:8;;;;37585:10;23535:34;37757:7;;37753:97;;23535:34;22089:4;37790:10;;37789:17;;-1:-1:-1;23477:22:0;37825:9;37753:97;23666:27;37870:1;:7;37866:97;;23666:27;22089:4;37903:10;;37902:17;;-1:-1:-1;23608:22:0;37938:9;37866:97;23789:24;37983:1;:7;37979:97;;23789:24;22089:4;38016:10;;38015:17;;-1:-1:-1;23732:21:0;38051:9;37979:97;23909:22;38096:1;:7;38092:97;;23909:22;22089:4;38129:10;;38128:17;;-1:-1:-1;23852:21:0;38164:9;38092:97;24027:21;38209:1;:7;38205:97;;24027:21;22089:4;38242:10;;38241:17;;-1:-1:-1;23970:21:0;38277:9;38205:97;24144:21;38322:1;:7;38318:97;;24144:21;22089:4;38355:10;;;38354:17;;38390:9;38318:97;24261:21;38435:1;:7;38431:97;;24261:21;22089:4;38468:10;;38467:17;;-1:-1:-1;24204:20:0;38503:9;38431:97;24378:21;38548:1;:7;38544:97;;24378:21;22089:4;38581:10;;38580:17;;-1:-1:-1;24321:20:0;38616:9;38544:97;24497:21;38661:1;:8;38657:100;;24497:21;22089:4;38695:10;;38694:18;;-1:-1:-1;24439:20:0;38731:10;38657:100;24616:21;38777:1;:8;38773:100;;24616:21;22089:4;38811:10;;38810:18;;-1:-1:-1;24559:19:0;38847:10;38773:100;39412:8;22089:4;39450:1;:10;22089:4;;39425:1;:10;39424:21;39423:38;;;;;:::i;:::-;;;-1:-1:-1;39476:16:0;22089:4;39496:5;;;39495:16;;-1:-1:-1;39616:1:0;;22089:4;39853:15;;;39852:26;;-1:-1:-1;39912:1:0;39852:26;39906:7;39893:20;22089:4;39937:15;;;39936:26;;-1:-1:-1;39996:1:0;39936:26;39990:7;39977:20;22089:4;40021:15;;;40020:26;;-1:-1:-1;40080:1:0;40020:26;40074:7;40061:20;22089:4;40105:15;;;40104:26;;-1:-1:-1;40164:1:0;40104:26;40158:7;40145:20;22089:4;40189:15;;;40188:26;;-1:-1:-1;40248:2:0;40188:26;40242:8;40229:21;40439:1;40426:14;40755:3;40736:15;;;40735:23;;35246:5531;-1:-1:-1;;;;;;;35246:5531:0:o;7968:3260::-;-1:-1:-1;;;10558:3:0;10551:79;;;10771:66;10765:4;10758:80;10915:1;10909:4;10902:15;9951:73;9120:2;9155:18;;;9201;;;9125:4;9197:29;;;9992:1;9988:14;9105:18;;;;9977:26;;;;9251:18;;;;9299;;;9295:29;;;10009:2;10005:17;9973:50;;;;9951:73;9933:3;9915:120;10984:4;10977:26;11214:3;;11204:14;91256:146;91322:17;91364:30;91381:4;:12;;;91364:16;:30::i;48025:834::-;48085:7;48318:6;;;:18;;;44063:4;48328:1;:8;48318:18;48314:538;;;-1:-1:-1;44063:4:0;48353:10;;48314:538;48385:6;48381:471;;-1:-1:-1;48415:1:0;48408:8;;48381:471;44063:4;48438:1;:8;48434:418;;;-1:-1:-1;48470:1:0;48463:8;;48434:418;44127:7;44063:4;44127:1;:7;:::i;:::-;48493:1;:8;48489:363;;;48525:11;48531:1;48534;48525:5;:11::i;48489:363::-;44174:7;44063:4;44174:1;:7;:::i;:::-;48558:1;:9;48554:298;;;48584:14;48601:11;48607:1;48610;48601:5;:11::i;:::-;48584:28;;48634:21;48640:6;48648;48634:5;:21::i;48554:298::-;48688:11;48702:20;48717:1;48720;48702:14;:20::i;:::-;48688:34;;48737:16;48756:42;48760:34;48766:3;44239:5;48760;:34::i;48756:42::-;48737:61;;48822:18;48826:3;48831:8;48822:3;:18::i;196:127:1:-;257:10;252:3;248:20;245:1;238:31;288:4;285:1;278:15;312:4;309:1;302:15;328:118;414:5;407:13;400:21;393:5;390:32;380:60;;436:1;433;426:12;451:964;502:5;532:6;575:2;563:9;558:3;554:19;550:28;547:48;;;591:1;588;581:12;547:48;624:2;618:9;654:15;;;;699:18;684:34;;720:22;;;681:62;678:88;;;746:18;;:::i;:::-;786:10;782:2;775:22;815:6;806:15;;858:9;845:23;837:6;830:39;930:2;919:9;915:18;902:32;897:2;889:6;885:15;878:57;996:2;985:9;981:18;968:32;963:2;955:6;951:15;944:57;1062:2;1051:9;1047:18;1034:32;1029:2;1021:6;1017:15;1010:57;1129:3;1118:9;1114:19;1101:33;1095:3;1087:6;1083:16;1076:59;1197:3;1186:9;1182:19;1169:33;1163:3;1155:6;1151:16;1144:59;1265:3;1254:9;1250:19;1237:33;1231:3;1223:6;1219:16;1212:59;1323:3;1312:9;1308:19;1295:33;1280:48;;1337:30;1359:7;1337:30;:::i;:::-;1395:3;1383:16;1376:33;451:964;;-1:-1:-1;;451:964:1:o;1420:291::-;1510:6;1518;1571:3;1559:9;1550:7;1546:23;1542:33;1539:53;;;1588:1;1585;1578:12;1539:53;1611:42;1645:7;1634:9;1611:42;:::i;:::-;1601:52;1700:3;1685:19;;;;1672:33;;-1:-1:-1;;;1420:291:1:o;1924:316::-;2001:6;2009;2017;2070:2;2058:9;2049:7;2045:23;2041:32;2038:52;;;2086:1;2083;2076:12;2038:52;-1:-1:-1;;2109:23:1;;;2179:2;2164:18;;2151:32;;-1:-1:-1;2230:2:1;2215:18;;;2202:32;;1924:316;-1:-1:-1;1924:316:1:o;2245:180::-;2304:6;2357:2;2345:9;2336:7;2332:23;2328:32;2325:52;;;2373:1;2370;2363:12;2325:52;-1:-1:-1;2396:23:1;;2245:180;-1:-1:-1;2245:180:1:o;3437:222::-;3518:6;3571:3;3559:9;3550:7;3546:23;3542:33;3539:53;;;3588:1;3585;3578:12;3539:53;3611:42;3645:7;3634:9;3611:42;:::i;3856:446::-;3939:6;3947;3955;3963;4016:3;4004:9;3995:7;3991:23;3987:33;3984:53;;;4033:1;4030;4023:12;3984:53;4069:9;4056:23;4046:33;;4126:2;4115:9;4111:18;4098:32;4088:42;;4180:2;4169:9;4165:18;4152:32;4193:28;4215:5;4193:28;:::i;:::-;3856:446;;;;-1:-1:-1;4240:5:1;;4292:2;4277:18;4264:32;;-1:-1:-1;;3856:446:1:o;4307:781::-;4390:6;4421:3;4465:2;4453:9;4444:7;4440:23;4436:32;4433:52;;;4481:1;4478;4471:12;4433:52;4530:7;4523:4;4512:9;4508:20;4504:34;4494:62;;4552:1;4549;4542:12;4494:62;4585:2;4579:9;4627:2;4619:6;4615:15;4696:6;4684:10;4681:22;4660:18;4648:10;4645:34;4642:62;4639:88;;;4707:18;;:::i;:::-;4743:2;4736:22;4807:18;;;;4778:6;4837:19;;;4834:39;;;4869:1;4866;4859:12;4834:39;4893:9;4911:146;4927:6;4922:3;4919:15;4911:146;;;4995:17;;4983:30;;5042:4;5033:14;;;;4944;4911:146;;;-1:-1:-1;5076:6:1;;4307:781;-1:-1:-1;;;;;4307:781:1:o;5474:340::-;5557:6;5565;5618:2;5606:9;5597:7;5593:23;5589:32;5586:52;;;5634:1;5631;5624:12;5586:52;5673:9;5660:23;5712:2;5705:5;5702:13;5692:41;;5729:1;5726;5719:12;5692:41;5752:5;5804:2;5789:18;;;;5776:32;;-1:-1:-1;;;5474:340:1:o;5819:248::-;5887:6;5895;5948:2;5936:9;5927:7;5923:23;5919:32;5916:52;;;5964:1;5961;5954:12;5916:52;-1:-1:-1;;5987:23:1;;;6057:2;6042:18;;;6029:32;;-1:-1:-1;5819:248:1:o;7248:131::-;-1:-1:-1;;;;;7323:31:1;;7313:42;;7303:70;;7369:1;7366;7359:12;7384:315;7452:6;7460;7513:2;7501:9;7492:7;7488:23;7484:32;7481:52;;;7529:1;7526;7519:12;7481:52;7568:9;7555:23;7587:31;7612:5;7587:31;:::i;7704:163::-;7771:20;;7831:10;7820:22;;7810:33;;7800:61;;7857:1;7854;7847:12;7872:813;7966:6;7974;8018:9;8009:7;8005:23;8048:3;8044:2;8040:12;8037:32;;;8065:1;8062;8055:12;8037:32;8089:4;8085:2;8081:13;8078:33;;;8107:1;8104;8097:12;8078:33;;8140:2;8134:9;8182:4;8174:6;8170:17;8253:6;8241:10;8238:22;8217:18;8205:10;8202:34;8199:62;8196:88;;;8264:18;;:::i;:::-;8300:2;8293:22;8339:28;8357:9;8339:28;:::i;:::-;8331:6;8324:44;8401:37;8434:2;8423:9;8419:18;8401:37;:::i;:::-;8396:2;8388:6;8384:15;8377:62;8489:2;8478:9;8474:18;8461:32;8537:5;8533:2;8522:21;8515:5;8512:32;8502:60;;8558:1;8555;8548:12;8502:60;8590:2;8578:15;;8571:30;8582:6;8673:4;8658:20;;;;8645:34;;-1:-1:-1;;;7872:813:1:o;8690:127::-;8751:10;8746:3;8742:20;8739:1;8732:31;8782:4;8779:1;8772:15;8806:4;8803:1;8796:15;8822:128;8862:3;8893:1;8889:6;8886:1;8883:13;8880:39;;;8899:18;;:::i;:::-;-1:-1:-1;8935:9:1;;8822:128::o;8955:342::-;9157:2;9139:21;;;9196:2;9176:18;;;9169:30;-1:-1:-1;;;9230:2:1;9215:18;;9208:48;9288:2;9273:18;;8955:342::o;9302:339::-;9504:2;9486:21;;;9543:2;9523:18;;;9516:30;-1:-1:-1;;;9577:2:1;9562:18;;9555:45;9632:2;9617:18;;9302:339::o;10340:::-;10542:2;10524:21;;;10581:2;10561:18;;;10554:30;-1:-1:-1;;;10615:2:1;10600:18;;10593:45;10670:2;10655:18;;10340:339::o;11031:125::-;11071:4;11099:1;11096;11093:8;11090:34;;;11104:18;;:::i;:::-;-1:-1:-1;11141:9:1;;11031:125::o;11161:267::-;11200:4;11229:9;;;11254:10;;-1:-1:-1;;;11273:19:1;;11266:27;;11250:44;11247:70;;;11297:18;;:::i;:::-;-1:-1:-1;;;;;11344:27:1;;11337:35;;11329:44;;11326:70;;;11376:18;;:::i;:::-;-1:-1:-1;;11413:9:1;;11161:267::o;11433:231::-;11473:4;-1:-1:-1;;;;;11571:10:1;;;;11541;;11593:12;;;11590:38;;;11608:18;;:::i;:::-;11645:13;;11433:231;-1:-1:-1;;;11433:231:1:o;12342:245::-;12409:6;12462:2;12450:9;12441:7;12437:23;12433:32;12430:52;;;12478:1;12475;12468:12;12430:52;12510:9;12504:16;12529:28;12551:5;12529:28;:::i;12592:251::-;12662:6;12715:2;12703:9;12694:7;12690:23;12686:32;12683:52;;;12731:1;12728;12721:12;12683:52;12763:9;12757:16;12782:31;12807:5;12782:31;:::i;13193:184::-;13263:6;13316:2;13304:9;13295:7;13291:23;13287:32;13284:52;;;13332:1;13329;13322:12;13284:52;-1:-1:-1;13355:16:1;;13193:184;-1:-1:-1;13193:184:1:o;14755:135::-;14794:3;-1:-1:-1;;14815:17:1;;14812:43;;;14835:18;;:::i;:::-;-1:-1:-1;14882:1:1;14871:13;;14755:135::o;15753:339::-;15955:2;15937:21;;;15994:2;15974:18;;;15967:30;-1:-1:-1;;;16028:2:1;16013:18;;16006:45;16083:2;16068:18;;15753:339::o;16097:946::-;16189:6;16220:3;16264:2;16252:9;16243:7;16239:23;16235:32;16232:52;;;16280:1;16277;16270:12;16232:52;16313:2;16307:9;16343:15;;;;16388:18;16373:34;;16409:22;;;16370:62;16367:88;;;16435:18;;:::i;:::-;16475:10;16471:2;16464:22;16516:9;16510:16;16502:6;16495:32;16581:2;16570:9;16566:18;16560:25;16555:2;16547:6;16543:15;16536:50;16640:2;16629:9;16625:18;16619:25;16614:2;16606:6;16602:15;16595:50;16699:2;16688:9;16684:18;16678:25;16673:2;16665:6;16661:15;16654:50;16759:3;16748:9;16744:19;16738:26;16732:3;16724:6;16720:16;16713:52;16820:3;16809:9;16805:19;16799:26;16793:3;16785:6;16781:16;16774:52;16881:3;16870:9;16866:19;16860:26;16854:3;16846:6;16842:16;16835:52;16930:3;16919:9;16915:19;16909:26;16896:39;;16944:28;16966:5;16944:28;:::i;:::-;17000:3;16988:16;;16981:31;;;;16992:6;16097:946;-1:-1:-1;;;16097:946:1:o;17388:127::-;17449:10;17444:3;17440:20;17437:1;17430:31;17480:4;17477:1;17470:15;17504:4;17501:1;17494:15;17520:127;17581:10;17576:3;17572:20;17569:1;17562:31;17612:4;17609:1;17602:15;17636:4;17633:1;17626:15;17652:168;17692:7;17758:1;17754;17750:6;17746:14;17743:1;17740:21;17735:1;17728:9;17721:17;17717:45;17714:71;;;17765:18;;:::i;:::-;-1:-1:-1;17805:9:1;;17652:168::o;17825:403::-;18027:2;18009:21;;;18066:2;18046:18;;;18039:30;18105:34;18100:2;18085:18;;18078:62;-1:-1:-1;;;18171:2:1;18156:18;;18149:37;18218:3;18203:19;;17825:403::o;18233:398::-;18435:2;18417:21;;;18474:2;18454:18;;;18447:30;18513:34;18508:2;18493:18;;18486:62;-1:-1:-1;;;18579:2:1;18564:18;;18557:32;18621:3;18606:19;;18233:398::o;18636:127::-;18697:10;18692:3;18688:20;18685:1;18678:31;18728:4;18725:1;18718:15;18752:4;18749:1;18742:15;18768:120;18808:1;18834;18824:35;;18839:18;;:::i;:::-;-1:-1:-1;18873:9:1;;18768:120::o;19563:553::-;19602:7;-1:-1:-1;;;;;19672:9:1;;;19700;;;19725:11;;;19744:10;;;19738:17;;19721:35;19718:61;;;19759:18;;:::i;:::-;-1:-1:-1;;;19835:1:1;19828:9;;19853:11;;;19873;;;19866:19;;19849:37;19846:63;;;19889:18;;:::i;:::-;19935:1;19932;19928:9;19918:19;;19982:1;19978:2;19973:11;19970:1;19966:19;19961:2;19957;19953:11;19949:37;19946:63;;;19989:18;;:::i;:::-;20054:1;20050:2;20045:11;20042:1;20038:19;20033:2;20029;20025:11;20021:37;20018:63;;;20061:18;;:::i;:::-;-1:-1:-1;;;20101:9:1;;;;;19563:553;-1:-1:-1;;;19563:553:1:o;21830:193::-;21869:1;21895;21885:35;;21900:18;;:::i;:::-;-1:-1:-1;;;21936:18:1;;-1:-1:-1;;21956:13:1;;21932:38;21929:64;;;21973:18;;:::i;:::-;-1:-1:-1;22007:10:1;;21830:193::o;22028:221::-;22067:4;22096:10;22156;;;;22126;;22178:12;;;22175:38;;;22193:18;;:::i;22254:265::-;22293:3;22321:9;;;22346:10;;-1:-1:-1;;;;;22365:27:1;;;22358:35;;22342:52;22339:78;;;22397:18;;:::i;:::-;-1:-1:-1;;;22444:19:1;;;22437:27;;22429:36;;22426:62;;;22468:18;;:::i;:::-;-1:-1:-1;;22504:9:1;;22254:265::o

Swarm Source

ipfs://ee478acafbb18cfc986294a7b7b8431a058e742dfd924976abd552d038da8a62

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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