Contract 0xcfa0451D8D1F08504Fa44a6f72D00F455b858a1d

Contract Overview

Balance:
0 Ether
Txn Hash
Method
Block
From
To
Value
0xa3cc992952235b09917836419b0c6495e004412f1be3f8f8f8c39d8185ace9cc0x615fd962107513502019-04-16 0:15:321263 days 23 hrs ago0xa2f79147143e9100e1dd65df277ac54825197148 IN  Create: OperationImpl0 Ether0.0647484110
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x2c78c5368707f2b1be9d12c948f5754d5df38870b1b52be06e1a24f2a33ca5d8335848962022-09-01 17:25:3629 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x2989bea770b23032ec1c42b2f8847860f19cffc28d6a4951ad7d6e0e94da7803335848722022-09-01 17:23:2829 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xe8498ae9b8dcd35b7ebbc2cbc9a3686ccf3239e4a163a32dedbf14049cfcbd4f335847872022-09-01 17:16:5229 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x74e1c3fcac5f082e04e26017a3fc2c359680449efd840d80fdbcdb869602af6f335847672022-09-01 17:15:2829 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x3eb8b2ebac1653c27e1b8b2c77f5da5a3810847094abf555cc7e54e362b65112335847222022-09-01 17:12:1229 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x14ec91d3da6d9146c0c0a0814adf43ec4d6d041fbd5692887b4dba3c15bf9fa1335847012022-09-01 17:10:2429 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xfef1a7e9a591d74df87e63e195345f3851aa4dbcca29a3f475180ddb173d0851335846642022-09-01 17:07:2029 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x1c42970a8f0179935d986134ad8df4803602b34b715058c67227f69ec9acccf4335846042022-09-01 17:02:3629 days 6 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x7c7a0aea99bc9629e0ebce5870f6d01b9fb02f6928e52bb1f8e7d6f39f209096335555352022-08-31 3:13:4830 days 20 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x7d78aafd782bef6f5a0adca7b697f4c3de8c3d7ea8090253653dcfe2a4f6e176335080672022-08-28 10:14:0033 days 13 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x46472005dd44fbd706e9cab4877b7f79ec573266228559972946330d7fa9f2c3335079852022-08-28 10:05:5233 days 13 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xa753536cd717b23f854eb7f123f7cf2c14c453e0fcf1729f5be43470daffae11334354032022-08-23 23:23:2838 days 19 mins ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x8e35eccfed58d0b76b4c64be80aa8f1b1f6f9be853c4316abd0e90c3a694d9e9334238882022-08-23 5:34:4038 days 18 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x73b56ea365d4ca3daba7b975f4c0887828c9e7345c1b9fb0cb9eb2b15d68d7b5334235112022-08-23 4:57:2038 days 18 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x694cda7a077bc257a0a48ac3313f28ef4917e7c2cbe94a8f70beefa9c512d02a334235062022-08-23 4:56:4838 days 18 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xad22beba839ce144b18ef272bec1e7a9014a91595cf132659827aeae426eb30b334233942022-08-23 4:46:0038 days 18 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xb32614d2e780668e66d51901db19f11de813099844527d1c68315acd7e0a7f5d334228202022-08-23 3:53:0438 days 19 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xc4d38e8ce9a0d8e23c366dde866e1f001f04be1cc9b2c456313ba086fcc96624334228002022-08-23 3:50:4438 days 19 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xd93bd8b4c829c1b35421c09b61db6c8c6e043c3f08303318e269587de4b2df9a334226942022-08-23 3:41:2438 days 20 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x2ac63b55ccd76a2d0af592e330c1375780a264c6ad4a75b29884930178dec62b334107722022-08-22 8:59:0439 days 14 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x408b92ff81cbcb9176ee531b3cc00f8375ec3d40025f7114f9b52a74c566ed28333886172022-08-20 22:17:5241 days 1 hr ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xe1419b436593bad016c9547898ed30da16b0690ad319e62fd94ddbe09f589cb4333545042022-08-18 21:06:4443 days 2 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0xa9b0063ac397e999391b935b9095ff5e7d3bf7f8ea41567c7808d61c4c0cfa82333544872022-08-18 21:05:2443 days 2 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x64f82c2ef4abe594e7f973373dce2728412910fcacdbdeb054616ee5b87c6b38333540392022-08-18 20:26:4843 days 3 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
0x8fe634544f4d3f733382ef1975eeedfe845b122c2020524e3b02e8a837de9172333540132022-08-18 20:24:4043 days 3 hrs ago 0x4ec3570cadaaee08ae384779b0f3a45ef85289de 0xcfa0451d8d1f08504fa44a6f72d00f455b858a1d0 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
OperationImpl

Compiler Version
v0.5.7+commit.6da8b019

Optimization Enabled:
Yes with 10000 runs

Other Settings:
byzantium EvmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-05-21
*/

/**
 *Submitted for verification at Etherscan.io on 2019-05-07
*/

/*

    Copyright 2019 dYdX Trading Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

*/

pragma solidity 0.5.7;
pragma experimental ABIEncoderV2;

// File: openzeppelin-solidity/contracts/math/SafeMath.sol

/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error
 */
library SafeMath {
    /**
    * @dev Multiplies two unsigned integers, reverts on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
    }

    /**
    * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
    * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    /**
    * @dev Adds two unsigned integers, reverts on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
    }

    /**
    * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
    * reverts when dividing by zero.
    */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}

// File: contracts/protocol/lib/Require.sol

/**
 * @title Require
 * @author dYdX
 *
 * Stringifies parameters to pretty-print revert messages. Costs more gas than regular require()
 */
library Require {

    // ============ Constants ============

    uint256 constant ASCII_ZERO = 48; // '0'
    uint256 constant ASCII_RELATIVE_ZERO = 87; // 'a' - 10
    uint256 constant ASCII_LOWER_EX = 120; // 'x'
    bytes2 constant COLON = 0x3a20; // ': '
    bytes2 constant COMMA = 0x2c20; // ', '
    bytes2 constant LPAREN = 0x203c; // ' <'
    byte constant RPAREN = 0x3e; // '>'
    uint256 constant FOUR_BIT_MASK = 0xf;

    // ============ Library Functions ============

    function that(
        bool must,
        bytes32 file,
        bytes32 reason
    )
        internal
        pure
    {
        if (!must) {
            revert(
                string(
                    abi.encodePacked(
                        stringify(file),
                        COLON,
                        stringify(reason)
                    )
                )
            );
        }
    }

    function that(
        bool must,
        bytes32 file,
        bytes32 reason,
        uint256 payloadA
    )
        internal
        pure
    {
        if (!must) {
            revert(
                string(
                    abi.encodePacked(
                        stringify(file),
                        COLON,
                        stringify(reason),
                        LPAREN,
                        stringify(payloadA),
                        RPAREN
                    )
                )
            );
        }
    }

    function that(
        bool must,
        bytes32 file,
        bytes32 reason,
        uint256 payloadA,
        uint256 payloadB
    )
        internal
        pure
    {
        if (!must) {
            revert(
                string(
                    abi.encodePacked(
                        stringify(file),
                        COLON,
                        stringify(reason),
                        LPAREN,
                        stringify(payloadA),
                        COMMA,
                        stringify(payloadB),
                        RPAREN
                    )
                )
            );
        }
    }

    function that(
        bool must,
        bytes32 file,
        bytes32 reason,
        address payloadA
    )
        internal
        pure
    {
        if (!must) {
            revert(
                string(
                    abi.encodePacked(
                        stringify(file),
                        COLON,
                        stringify(reason),
                        LPAREN,
                        stringify(payloadA),
                        RPAREN
                    )
                )
            );
        }
    }

    function that(
        bool must,
        bytes32 file,
        bytes32 reason,
        address payloadA,
        uint256 payloadB
    )
        internal
        pure
    {
        if (!must) {
            revert(
                string(
                    abi.encodePacked(
                        stringify(file),
                        COLON,
                        stringify(reason),
                        LPAREN,
                        stringify(payloadA),
                        COMMA,
                        stringify(payloadB),
                        RPAREN
                    )
                )
            );
        }
    }

    function that(
        bool must,
        bytes32 file,
        bytes32 reason,
        address payloadA,
        uint256 payloadB,
        uint256 payloadC
    )
        internal
        pure
    {
        if (!must) {
            revert(
                string(
                    abi.encodePacked(
                        stringify(file),
                        COLON,
                        stringify(reason),
                        LPAREN,
                        stringify(payloadA),
                        COMMA,
                        stringify(payloadB),
                        COMMA,
                        stringify(payloadC),
                        RPAREN
                    )
                )
            );
        }
    }

    // ============ Private Functions ============

    function stringify(
        bytes32 input
    )
        private
        pure
        returns (bytes memory)
    {
        // put the input bytes into the result
        bytes memory result = abi.encodePacked(input);

        // determine the length of the input by finding the location of the last non-zero byte
        for (uint256 i = 32; i > 0; ) {
            // reverse-for-loops with unsigned integer
            /* solium-disable-next-line security/no-modify-for-iter-var */
            i--;

            // find the last non-zero byte in order to determine the length
            if (result[i] != 0) {
                uint256 length = i + 1;

                /* solium-disable-next-line security/no-inline-assembly */
                assembly {
                    mstore(result, length) // r.length = length;
                }

                return result;
            }
        }

        // all bytes are zero
        return new bytes(0);
    }

    function stringify(
        uint256 input
    )
        private
        pure
        returns (bytes memory)
    {
        if (input == 0) {
            return "0";
        }

        // get the final string length
        uint256 j = input;
        uint256 length;
        while (j != 0) {
            length++;
            j /= 10;
        }

        // allocate the string
        bytes memory bstr = new bytes(length);

        // populate the string starting with the least-significant character
        j = input;
        for (uint256 i = length; i > 0; ) {
            // reverse-for-loops with unsigned integer
            /* solium-disable-next-line security/no-modify-for-iter-var */
            i--;

            // take last decimal digit
            bstr[i] = byte(uint8(ASCII_ZERO + (j % 10)));

            // remove the last decimal digit
            j /= 10;
        }

        return bstr;
    }

    function stringify(
        address input
    )
        private
        pure
        returns (bytes memory)
    {
        uint256 z = uint256(input);

        // addresses are "0x" followed by 20 bytes of data which take up 2 characters each
        bytes memory result = new bytes(42);

        // populate the result with "0x"
        result[0] = byte(uint8(ASCII_ZERO));
        result[1] = byte(uint8(ASCII_LOWER_EX));

        // for each byte (starting from the lowest byte), populate the result with two characters
        for (uint256 i = 0; i < 20; i++) {
            // each byte takes two characters
            uint256 shift = i * 2;

            // populate the least-significant character
            result[41 - shift] = char(z & FOUR_BIT_MASK);
            z = z >> 4;

            // populate the most-significant character
            result[40 - shift] = char(z & FOUR_BIT_MASK);
            z = z >> 4;
        }

        return result;
    }

    function char(
        uint256 input
    )
        private
        pure
        returns (byte)
    {
        // return ASCII digit (0-9)
        if (input < 10) {
            return byte(uint8(input + ASCII_ZERO));
        }

        // return ASCII letter (a-f)
        return byte(uint8(input + ASCII_RELATIVE_ZERO));
    }
}

// File: contracts/protocol/lib/Math.sol

/**
 * @title Math
 * @author dYdX
 *
 * Library for non-standard Math functions
 */
library Math {
    using SafeMath for uint256;

    // ============ Constants ============

    bytes32 constant FILE = "Math";

    // ============ Library Functions ============

    /*
     * Return target * (numerator / denominator).
     */
    function getPartial(
        uint256 target,
        uint256 numerator,
        uint256 denominator
    )
        internal
        pure
        returns (uint256)
    {
        return target.mul(numerator).div(denominator);
    }

    /*
     * Return target * (numerator / denominator), but rounded up.
     */
    function getPartialRoundUp(
        uint256 target,
        uint256 numerator,
        uint256 denominator
    )
        internal
        pure
        returns (uint256)
    {
        if (target == 0 || numerator == 0) {
            // SafeMath will check for zero denominator
            return SafeMath.div(0, denominator);
        }
        return target.mul(numerator).sub(1).div(denominator).add(1);
    }

    function to128(
        uint256 number
    )
        internal
        pure
        returns (uint128)
    {
        uint128 result = uint128(number);
        Require.that(
            result == number,
            FILE,
            "Unsafe cast to uint128"
        );
        return result;
    }

    function to96(
        uint256 number
    )
        internal
        pure
        returns (uint96)
    {
        uint96 result = uint96(number);
        Require.that(
            result == number,
            FILE,
            "Unsafe cast to uint96"
        );
        return result;
    }

    function to32(
        uint256 number
    )
        internal
        pure
        returns (uint32)
    {
        uint32 result = uint32(number);
        Require.that(
            result == number,
            FILE,
            "Unsafe cast to uint32"
        );
        return result;
    }

    function min(
        uint256 a,
        uint256 b
    )
        internal
        pure
        returns (uint256)
    {
        return a < b ? a : b;
    }

    function max(
        uint256 a,
        uint256 b
    )
        internal
        pure
        returns (uint256)
    {
        return a > b ? a : b;
    }
}

// File: contracts/protocol/lib/Types.sol

/**
 * @title Types
 * @author dYdX
 *
 * Library for interacting with the basic structs used in Solo
 */
library Types {
    using Math for uint256;

    // ============ AssetAmount ============

    enum AssetDenomination {
        Wei, // the amount is denominated in wei
        Par  // the amount is denominated in par
    }

    enum AssetReference {
        Delta, // the amount is given as a delta from the current value
        Target // the amount is given as an exact number to end up at
    }

    struct AssetAmount {
        bool sign; // true if positive
        AssetDenomination denomination;
        AssetReference ref;
        uint256 value;
    }

    // ============ Par (Principal Amount) ============

    // Total borrow and supply values for a market
    struct TotalPar {
        uint128 borrow;
        uint128 supply;
    }

    // Individual principal amount for an account
    struct Par {
        bool sign; // true if positive
        uint128 value;
    }

    function zeroPar()
        internal
        pure
        returns (Par memory)
    {
        return Par({
            sign: false,
            value: 0
        });
    }

    function sub(
        Par memory a,
        Par memory b
    )
        internal
        pure
        returns (Par memory)
    {
        return add(a, negative(b));
    }

    function add(
        Par memory a,
        Par memory b
    )
        internal
        pure
        returns (Par memory)
    {
        Par memory result;
        if (a.sign == b.sign) {
            result.sign = a.sign;
            result.value = SafeMath.add(a.value, b.value).to128();
        } else {
            if (a.value >= b.value) {
                result.sign = a.sign;
                result.value = SafeMath.sub(a.value, b.value).to128();
            } else {
                result.sign = b.sign;
                result.value = SafeMath.sub(b.value, a.value).to128();
            }
        }
        return result;
    }

    function equals(
        Par memory a,
        Par memory b
    )
        internal
        pure
        returns (bool)
    {
        if (a.value == b.value) {
            if (a.value == 0) {
                return true;
            }
            return a.sign == b.sign;
        }
        return false;
    }

    function negative(
        Par memory a
    )
        internal
        pure
        returns (Par memory)
    {
        return Par({
            sign: !a.sign,
            value: a.value
        });
    }

    function isNegative(
        Par memory a
    )
        internal
        pure
        returns (bool)
    {
        return !a.sign && a.value > 0;
    }

    function isPositive(
        Par memory a
    )
        internal
        pure
        returns (bool)
    {
        return a.sign && a.value > 0;
    }

    function isZero(
        Par memory a
    )
        internal
        pure
        returns (bool)
    {
        return a.value == 0;
    }

    // ============ Wei (Token Amount) ============

    // Individual token amount for an account
    struct Wei {
        bool sign; // true if positive
        uint256 value;
    }

    function zeroWei()
        internal
        pure
        returns (Wei memory)
    {
        return Wei({
            sign: false,
            value: 0
        });
    }

    function sub(
        Wei memory a,
        Wei memory b
    )
        internal
        pure
        returns (Wei memory)
    {
        return add(a, negative(b));
    }

    function add(
        Wei memory a,
        Wei memory b
    )
        internal
        pure
        returns (Wei memory)
    {
        Wei memory result;
        if (a.sign == b.sign) {
            result.sign = a.sign;
            result.value = SafeMath.add(a.value, b.value);
        } else {
            if (a.value >= b.value) {
                result.sign = a.sign;
                result.value = SafeMath.sub(a.value, b.value);
            } else {
                result.sign = b.sign;
                result.value = SafeMath.sub(b.value, a.value);
            }
        }
        return result;
    }

    function equals(
        Wei memory a,
        Wei memory b
    )
        internal
        pure
        returns (bool)
    {
        if (a.value == b.value) {
            if (a.value == 0) {
                return true;
            }
            return a.sign == b.sign;
        }
        return false;
    }

    function negative(
        Wei memory a
    )
        internal
        pure
        returns (Wei memory)
    {
        return Wei({
            sign: !a.sign,
            value: a.value
        });
    }

    function isNegative(
        Wei memory a
    )
        internal
        pure
        returns (bool)
    {
        return !a.sign && a.value > 0;
    }

    function isPositive(
        Wei memory a
    )
        internal
        pure
        returns (bool)
    {
        return a.sign && a.value > 0;
    }

    function isZero(
        Wei memory a
    )
        internal
        pure
        returns (bool)
    {
        return a.value == 0;
    }
}

// File: contracts/protocol/lib/Account.sol

/**
 * @title Account
 * @author dYdX
 *
 * Library of structs and functions that represent an account
 */
library Account {
    // ============ Enums ============

    /*
     * Most-recently-cached account status.
     *
     * Normal: Can only be liquidated if the account values are violating the global margin-ratio.
     * Liquid: Can be liquidated no matter the account values.
     *         Can be vaporized if there are no more positive account values.
     * Vapor:  Has only negative (or zeroed) account values. Can be vaporized.
     *
     */
    enum Status {
        Normal,
        Liquid,
        Vapor
    }

    // ============ Structs ============

    // Represents the unique key that specifies an account
    struct Info {
        address owner;  // The address that owns the account
        uint256 number; // A nonce that allows a single address to control many accounts
    }

    // The complete storage for any account
    struct Storage {
        mapping (uint256 => Types.Par) balances; // Mapping from marketId to principal
        Status status;
    }

    // ============ Library Functions ============

    function equals(
        Info memory a,
        Info memory b
    )
        internal
        pure
        returns (bool)
    {
        return a.owner == b.owner && a.number == b.number;
    }
}

// File: contracts/protocol/interfaces/IAutoTrader.sol

/**
 * @title IAutoTrader
 * @author dYdX
 *
 * Interface that Auto-Traders for Solo must implement in order to approve trades.
 */
contract IAutoTrader {

    // ============ Public Functions ============

    /**
     * Allows traders to make trades approved by this smart contract. The active trader's account is
     * the takerAccount and the passive account (for which this contract approves trades
     * on-behalf-of) is the makerAccount.
     *
     * @param  inputMarketId   The market for which the trader specified the original amount
     * @param  outputMarketId  The market for which the trader wants the resulting amount specified
     * @param  makerAccount    The account for which this contract is making trades
     * @param  takerAccount    The account requesting the trade
     * @param  oldInputPar     The old principal amount for the makerAccount for the inputMarketId
     * @param  newInputPar     The new principal amount for the makerAccount for the inputMarketId
     * @param  inputWei        The change in token amount for the makerAccount for the inputMarketId
     * @param  data            Arbitrary data passed in by the trader
     * @return                 The AssetAmount for the makerAccount for the outputMarketId
     */
    function getTradeCost(
        uint256 inputMarketId,
        uint256 outputMarketId,
        Account.Info memory makerAccount,
        Account.Info memory takerAccount,
        Types.Par memory oldInputPar,
        Types.Par memory newInputPar,
        Types.Wei memory inputWei,
        bytes memory data
    )
        public
        returns (Types.AssetAmount memory);
}

// File: contracts/protocol/interfaces/ICallee.sol

/**
 * @title ICallee
 * @author dYdX
 *
 * Interface that Callees for Solo must implement in order to ingest data.
 */
contract ICallee {

    // ============ Public Functions ============

    /**
     * Allows users to send this contract arbitrary data.
     *
     * @param  sender       The msg.sender to Solo
     * @param  accountInfo  The account from which the data is being sent
     * @param  data         Arbitrary data given by the sender
     */
    function callFunction(
        address sender,
        Account.Info memory accountInfo,
        bytes memory data
    )
        public;
}

// File: contracts/protocol/lib/Actions.sol

/**
 * @title Actions
 * @author dYdX
 *
 * Library that defines and parses valid Actions
 */
library Actions {

    // ============ Constants ============

    bytes32 constant FILE = "Actions";

    // ============ Enums ============

    enum ActionType {
        Deposit,   // supply tokens
        Withdraw,  // borrow tokens
        Transfer,  // transfer balance between accounts
        Buy,       // buy an amount of some token (externally)
        Sell,      // sell an amount of some token (externally)
        Trade,     // trade tokens against another account
        Liquidate, // liquidate an undercollateralized or expiring account
        Vaporize,  // use excess tokens to zero-out a completely negative account
        Call       // send arbitrary data to an address
    }

    enum AccountLayout {
        OnePrimary,
        TwoPrimary,
        PrimaryAndSecondary
    }

    enum MarketLayout {
        ZeroMarkets,
        OneMarket,
        TwoMarkets
    }

    // ============ Structs ============

    /*
     * Arguments that are passed to Solo in an ordered list as part of a single operation.
     * Each ActionArgs has an actionType which specifies which action struct that this data will be
     * parsed into before being processed.
     */
    struct ActionArgs {
        ActionType actionType;
        uint256 accountId;
        Types.AssetAmount amount;
        uint256 primaryMarketId;
        uint256 secondaryMarketId;
        address otherAddress;
        uint256 otherAccountId;
        bytes data;
    }

    // ============ Action Types ============

    /*
     * Moves tokens from an address to Solo. Can either repay a borrow or provide additional supply.
     */
    struct DepositArgs {
        Types.AssetAmount amount;
        Account.Info account;
        uint256 market;
        address from;
    }

    /*
     * Moves tokens from Solo to another address. Can either borrow tokens or reduce the amount
     * previously supplied.
     */
    struct WithdrawArgs {
        Types.AssetAmount amount;
        Account.Info account;
        uint256 market;
        address to;
    }

    /*
     * Transfers balance between two accounts. The msg.sender must be an operator for both accounts.
     * The amount field applies to accountOne.
     * This action does not require any token movement since the trade is done internally to Solo.
     */
    struct TransferArgs {
        Types.AssetAmount amount;
        Account.Info accountOne;
        Account.Info accountTwo;
        uint256 market;
    }

    /*
     * Acquires a certain amount of tokens by spending other tokens. Sends takerMarket tokens to the
     * specified exchangeWrapper contract and expects makerMarket tokens in return. The amount field
     * applies to the makerMarket.
     */
    struct BuyArgs {
        Types.AssetAmount amount;
        Account.Info account;
        uint256 makerMarket;
        uint256 takerMarket;
        address exchangeWrapper;
        bytes orderData;
    }

    /*
     * Spends a certain amount of tokens to acquire other tokens. Sends takerMarket tokens to the
     * specified exchangeWrapper and expects makerMarket tokens in return. The amount field applies
     * to the takerMarket.
     */
    struct SellArgs {
        Types.AssetAmount amount;
        Account.Info account;
        uint256 takerMarket;
        uint256 makerMarket;
        address exchangeWrapper;
        bytes orderData;
    }

    /*
     * Trades balances between two accounts using any external contract that implements the
     * AutoTrader interface. The AutoTrader contract must be an operator for the makerAccount (for
     * which it is trading on-behalf-of). The amount field applies to the makerAccount and the
     * inputMarket. This proposed change to the makerAccount is passed to the AutoTrader which will
     * quote a change for the makerAccount in the outputMarket (or will disallow the trade).
     * This action does not require any token movement since the trade is done internally to Solo.
     */
    struct TradeArgs {
        Types.AssetAmount amount;
        Account.Info takerAccount;
        Account.Info makerAccount;
        uint256 inputMarket;
        uint256 outputMarket;
        address autoTrader;
        bytes tradeData;
    }

    /*
     * Each account must maintain a certain margin-ratio (specified globally). If the account falls
     * below this margin-ratio, it can be liquidated by any other account. This allows anyone else
     * (arbitrageurs) to repay any borrowed asset (owedMarket) of the liquidating account in
     * exchange for any collateral asset (heldMarket) of the liquidAccount. The ratio is determined
     * by the price ratio (given by the oracles) plus a spread (specified globally). Liquidating an
     * account also sets a flag on the account that the account is being liquidated. This allows
     * anyone to continue liquidating the account until there are no more borrows being taken by the
     * liquidating account. Liquidators do not have to liquidate the entire account all at once but
     * can liquidate as much as they choose. The liquidating flag allows liquidators to continue
     * liquidating the account even if it becomes collateralized through partial liquidation or
     * price movement.
     */
    struct LiquidateArgs {
        Types.AssetAmount amount;
        Account.Info solidAccount;
        Account.Info liquidAccount;
        uint256 owedMarket;
        uint256 heldMarket;
    }

    /*
     * Similar to liquidate, but vaporAccounts are accounts that have only negative balances
     * remaining. The arbitrageur pays back the negative asset (owedMarket) of the vaporAccount in
     * exchange for a collateral asset (heldMarket) at a favorable spread. However, since the
     * liquidAccount has no collateral assets, the collateral must come from Solo's excess tokens.
     */
    struct VaporizeArgs {
        Types.AssetAmount amount;
        Account.Info solidAccount;
        Account.Info vaporAccount;
        uint256 owedMarket;
        uint256 heldMarket;
    }

    /*
     * Passes arbitrary bytes of data to an external contract that implements the Callee interface.
     * Does not change any asset amounts. This function may be useful for setting certain variables
     * on layer-two contracts for certain accounts without having to make a separate Ethereum
     * transaction for doing so. Also, the second-layer contracts can ensure that the call is coming
     * from an operator of the particular account.
     */
    struct CallArgs {
        Account.Info account;
        address callee;
        bytes data;
    }

    // ============ Helper Functions ============

    function getMarketLayout(
        ActionType actionType
    )
        internal
        pure
        returns (MarketLayout)
    {
        if (
            actionType == Actions.ActionType.Deposit
            || actionType == Actions.ActionType.Withdraw
            || actionType == Actions.ActionType.Transfer
        ) {
            return MarketLayout.OneMarket;
        }
        else if (actionType == Actions.ActionType.Call) {
            return MarketLayout.ZeroMarkets;
        }
        return MarketLayout.TwoMarkets;
    }

    function getAccountLayout(
        ActionType actionType
    )
        internal
        pure
        returns (AccountLayout)
    {
        if (
            actionType == Actions.ActionType.Transfer
            || actionType == Actions.ActionType.Trade
        ) {
            return AccountLayout.TwoPrimary;
        } else if (
            actionType == Actions.ActionType.Liquidate
            || actionType == Actions.ActionType.Vaporize
        ) {
            return AccountLayout.PrimaryAndSecondary;
        }
        return AccountLayout.OnePrimary;
    }

    // ============ Parsing Functions ============

    function parseDepositArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (DepositArgs memory)
    {
        assert(args.actionType == ActionType.Deposit);
        return DepositArgs({
            amount: args.amount,
            account: accounts[args.accountId],
            market: args.primaryMarketId,
            from: args.otherAddress
        });
    }

    function parseWithdrawArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (WithdrawArgs memory)
    {
        assert(args.actionType == ActionType.Withdraw);
        return WithdrawArgs({
            amount: args.amount,
            account: accounts[args.accountId],
            market: args.primaryMarketId,
            to: args.otherAddress
        });
    }

    function parseTransferArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (TransferArgs memory)
    {
        assert(args.actionType == ActionType.Transfer);
        return TransferArgs({
            amount: args.amount,
            accountOne: accounts[args.accountId],
            accountTwo: accounts[args.otherAccountId],
            market: args.primaryMarketId
        });
    }

    function parseBuyArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (BuyArgs memory)
    {
        assert(args.actionType == ActionType.Buy);
        return BuyArgs({
            amount: args.amount,
            account: accounts[args.accountId],
            makerMarket: args.primaryMarketId,
            takerMarket: args.secondaryMarketId,
            exchangeWrapper: args.otherAddress,
            orderData: args.data
        });
    }

    function parseSellArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (SellArgs memory)
    {
        assert(args.actionType == ActionType.Sell);
        return SellArgs({
            amount: args.amount,
            account: accounts[args.accountId],
            takerMarket: args.primaryMarketId,
            makerMarket: args.secondaryMarketId,
            exchangeWrapper: args.otherAddress,
            orderData: args.data
        });
    }

    function parseTradeArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (TradeArgs memory)
    {
        assert(args.actionType == ActionType.Trade);
        return TradeArgs({
            amount: args.amount,
            takerAccount: accounts[args.accountId],
            makerAccount: accounts[args.otherAccountId],
            inputMarket: args.primaryMarketId,
            outputMarket: args.secondaryMarketId,
            autoTrader: args.otherAddress,
            tradeData: args.data
        });
    }

    function parseLiquidateArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (LiquidateArgs memory)
    {
        assert(args.actionType == ActionType.Liquidate);
        return LiquidateArgs({
            amount: args.amount,
            solidAccount: accounts[args.accountId],
            liquidAccount: accounts[args.otherAccountId],
            owedMarket: args.primaryMarketId,
            heldMarket: args.secondaryMarketId
        });
    }

    function parseVaporizeArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (VaporizeArgs memory)
    {
        assert(args.actionType == ActionType.Vaporize);
        return VaporizeArgs({
            amount: args.amount,
            solidAccount: accounts[args.accountId],
            vaporAccount: accounts[args.otherAccountId],
            owedMarket: args.primaryMarketId,
            heldMarket: args.secondaryMarketId
        });
    }

    function parseCallArgs(
        Account.Info[] memory accounts,
        ActionArgs memory args
    )
        internal
        pure
        returns (CallArgs memory)
    {
        assert(args.actionType == ActionType.Call);
        return CallArgs({
            account: accounts[args.accountId],
            callee: args.otherAddress,
            data: args.data
        });
    }
}

// File: contracts/protocol/lib/Monetary.sol

/**
 * @title Monetary
 * @author dYdX
 *
 * Library for types involving money
 */
library Monetary {

    /*
     * The price of a base-unit of an asset.
     */
    struct Price {
        uint256 value;
    }

    /*
     * Total value of an some amount of an asset. Equal to (price * amount).
     */
    struct Value {
        uint256 value;
    }
}

// File: contracts/protocol/lib/Cache.sol

/**
 * @title Cache
 * @author dYdX
 *
 * Library for caching information about markets
 */
library Cache {
    using Cache for MarketCache;
    using Storage for Storage.State;

    // ============ Structs ============

    struct MarketInfo {
        bool isClosing;
        uint128 borrowPar;
        Monetary.Price price;
    }

    struct MarketCache {
        MarketInfo[] markets;
    }

    // ============ Setter Functions ============

    /**
     * Initialize an empty cache for some given number of total markets.
     */
    function create(
        uint256 numMarkets
    )
        internal
        pure
        returns (MarketCache memory)
    {
        return MarketCache({
            markets: new MarketInfo[](numMarkets)
        });
    }

    /**
     * Add market information (price and total borrowed par if the market is closing) to the cache.
     * Return true if the market information did not previously exist in the cache.
     */
    function addMarket(
        MarketCache memory cache,
        Storage.State storage state,
        uint256 marketId
    )
        internal
        view
        returns (bool)
    {
        if (cache.hasMarket(marketId)) {
            return false;
        }
        cache.markets[marketId].price = state.fetchPrice(marketId);
        if (state.markets[marketId].isClosing) {
            cache.markets[marketId].isClosing = true;
            cache.markets[marketId].borrowPar = state.getTotalPar(marketId).borrow;
        }
        return true;
    }

    // ============ Getter Functions ============

    function getNumMarkets(
        MarketCache memory cache
    )
        internal
        pure
        returns (uint256)
    {
        return cache.markets.length;
    }

    function hasMarket(
        MarketCache memory cache,
        uint256 marketId
    )
        internal
        pure
        returns (bool)
    {
        return cache.markets[marketId].price.value != 0;
    }

    function getIsClosing(
        MarketCache memory cache,
        uint256 marketId
    )
        internal
        pure
        returns (bool)
    {
        return cache.markets[marketId].isClosing;
    }

    function getPrice(
        MarketCache memory cache,
        uint256 marketId
    )
        internal
        pure
        returns (Monetary.Price memory)
    {
        return cache.markets[marketId].price;
    }

    function getBorrowPar(
        MarketCache memory cache,
        uint256 marketId
    )
        internal
        pure
        returns (uint128)
    {
        return cache.markets[marketId].borrowPar;
    }
}

// File: contracts/protocol/lib/Decimal.sol

/**
 * @title Decimal
 * @author dYdX
 *
 * Library that defines a fixed-point number with 18 decimal places.
 */
library Decimal {
    using SafeMath for uint256;

    // ============ Constants ============

    uint256 constant BASE = 10**18;

    // ============ Structs ============

    struct D256 {
        uint256 value;
    }

    // ============ Functions ============

    function one()
        internal
        pure
        returns (D256 memory)
    {
        return D256({ value: BASE });
    }

    function onePlus(
        D256 memory d
    )
        internal
        pure
        returns (D256 memory)
    {
        return D256({ value: d.value.add(BASE) });
    }

    function mul(
        uint256 target,
        D256 memory d
    )
        internal
        pure
        returns (uint256)
    {
        return Math.getPartial(target, d.value, BASE);
    }

    function div(
        uint256 target,
        D256 memory d
    )
        internal
        pure
        returns (uint256)
    {
        return Math.getPartial(target, BASE, d.value);
    }
}

// File: contracts/protocol/lib/Time.sol

/**
 * @title Time
 * @author dYdX
 *
 * Library for dealing with time, assuming timestamps fit within 32 bits (valid until year 2106)
 */
library Time {

    // ============ Library Functions ============

    function currentTime()
        internal
        view
        returns (uint32)
    {
        return Math.to32(block.timestamp);
    }
}

// File: contracts/protocol/lib/Interest.sol

/**
 * @title Interest
 * @author dYdX
 *
 * Library for managing the interest rate and interest indexes of Solo
 */
library Interest {
    using Math for uint256;
    using SafeMath for uint256;

    // ============ Constants ============

    bytes32 constant FILE = "Interest";
    uint64 constant BASE = 10**18;

    // ============ Structs ============

    struct Rate {
        uint256 value;
    }

    struct Index {
        uint96 borrow;
        uint96 supply;
        uint32 lastUpdate;
    }

    // ============ Library Functions ============

    /**
     * Get a new market Index based on the old index and market interest rate.
     * Calculate interest for borrowers by using the formula rate * time. Approximates
     * continuously-compounded interest when called frequently, but is much more
     * gas-efficient to calculate. For suppliers, the interest rate is adjusted by the earningsRate,
     * then prorated the across all suppliers.
     *
     * @param  index         The old index for a market
     * @param  rate          The current interest rate of the market
     * @param  totalPar      The total supply and borrow par values of the market
     * @param  earningsRate  The portion of the interest that is forwarded to the suppliers
     * @return               The updated index for a market
     */
    function calculateNewIndex(
        Index memory index,
        Rate memory rate,
        Types.TotalPar memory totalPar,
        Decimal.D256 memory earningsRate
    )
        internal
        view
        returns (Index memory)
    {
        (
            Types.Wei memory supplyWei,
            Types.Wei memory borrowWei
        ) = totalParToWei(totalPar, index);

        // get interest increase for borrowers
        uint32 currentTime = Time.currentTime();
        uint256 borrowInterest = rate.value.mul(uint256(currentTime).sub(index.lastUpdate));

        // get interest increase for suppliers
        uint256 supplyInterest;
        if (Types.isZero(supplyWei)) {
            supplyInterest = 0;
        } else {
            supplyInterest = Decimal.mul(borrowInterest, earningsRate);
            if (borrowWei.value < supplyWei.value) {
                supplyInterest = Math.getPartial(supplyInterest, borrowWei.value, supplyWei.value);
            }
        }
        assert(supplyInterest <= borrowInterest);

        return Index({
            borrow: Math.getPartial(index.borrow, borrowInterest, BASE).add(index.borrow).to96(),
            supply: Math.getPartial(index.supply, supplyInterest, BASE).add(index.supply).to96(),
            lastUpdate: currentTime
        });
    }

    function newIndex()
        internal
        view
        returns (Index memory)
    {
        return Index({
            borrow: BASE,
            supply: BASE,
            lastUpdate: Time.currentTime()
        });
    }

    /*
     * Convert a principal amount to a token amount given an index.
     */
    function parToWei(
        Types.Par memory input,
        Index memory index
    )
        internal
        pure
        returns (Types.Wei memory)
    {
        uint256 inputValue = uint256(input.value);
        if (input.sign) {
            return Types.Wei({
                sign: true,
                value: inputValue.getPartial(index.supply, BASE)
            });
        } else {
            return Types.Wei({
                sign: false,
                value: inputValue.getPartialRoundUp(index.borrow, BASE)
            });
        }
    }

    /*
     * Convert a token amount to a principal amount given an index.
     */
    function weiToPar(
        Types.Wei memory input,
        Index memory index
    )
        internal
        pure
        returns (Types.Par memory)
    {
        if (input.sign) {
            return Types.Par({
                sign: true,
                value: input.value.getPartial(BASE, index.supply).to128()
            });
        } else {
            return Types.Par({
                sign: false,
                value: input.value.getPartialRoundUp(BASE, index.borrow).to128()
            });
        }
    }

    /*
     * Convert the total supply and borrow principal amounts of a market to total supply and borrow
     * token amounts.
     */
    function totalParToWei(
        Types.TotalPar memory totalPar,
        Index memory index
    )
        internal
        pure
        returns (Types.Wei memory, Types.Wei memory)
    {
        Types.Par memory supplyPar = Types.Par({
            sign: true,
            value: totalPar.supply
        });
        Types.Par memory borrowPar = Types.Par({
            sign: false,
            value: totalPar.borrow
        });
        Types.Wei memory supplyWei = parToWei(supplyPar, index);
        Types.Wei memory borrowWei = parToWei(borrowPar, index);
        return (supplyWei, borrowWei);
    }
}

// File: contracts/protocol/interfaces/IErc20.sol

/**
 * @title IErc20
 * @author dYdX
 *
 * Interface for using ERC20 Tokens. We have to use a special interface to call ERC20 functions so
 * that we don't automatically revert when calling non-compliant tokens that have no return value for
 * transfer(), transferFrom(), or approve().
 */
interface IErc20 {
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 value
    );

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

    function totalSupply(
    )
        external
        view
        returns (uint256);

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

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

    function transfer(
        address to,
        uint256 value
    )
        external;

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

    function approve(
        address spender,
        uint256 value
    )
        external;

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

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

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

// File: contracts/protocol/lib/Token.sol

/**
 * @title Token
 * @author dYdX
 *
 * This library contains basic functions for interacting with ERC20 tokens. Modified to work with
 * tokens that don't adhere strictly to the ERC20 standard (for example tokens that don't return a
 * boolean value on success).
 */
library Token {

    // ============ Constants ============

    bytes32 constant FILE = "Token";

    // ============ Library Functions ============

    function balanceOf(
        address token,
        address owner
    )
        internal
        view
        returns (uint256)
    {
        return IErc20(token).balanceOf(owner);
    }

    function allowance(
        address token,
        address owner,
        address spender
    )
        internal
        view
        returns (uint256)
    {
        return IErc20(token).allowance(owner, spender);
    }

    function approve(
        address token,
        address spender,
        uint256 amount
    )
        internal
    {
        IErc20(token).approve(spender, amount);

        Require.that(
            checkSuccess(),
            FILE,
            "Approve failed"
        );
    }

    function approveMax(
        address token,
        address spender
    )
        internal
    {
        approve(
            token,
            spender,
            uint256(-1)
        );
    }

    function transfer(
        address token,
        address to,
        uint256 amount
    )
        internal
    {
        if (amount == 0 || to == address(this)) {
            return;
        }

        IErc20(token).transfer(to, amount);

        Require.that(
            checkSuccess(),
            FILE,
            "Transfer failed"
        );
    }

    function transferFrom(
        address token,
        address from,
        address to,
        uint256 amount
    )
        internal
    {
        if (amount == 0 || to == from) {
            return;
        }

        IErc20(token).transferFrom(from, to, amount);

        Require.that(
            checkSuccess(),
            FILE,
            "TransferFrom failed"
        );
    }

    // ============ Private Functions ============

    /**
     * Check the return value of the previous function up to 32 bytes. Return true if the previous
     * function returned 0 bytes or 32 bytes that are not all-zero.
     */
    function checkSuccess(
    )
        private
        pure
        returns (bool)
    {
        uint256 returnValue = 0;

        /* solium-disable-next-line security/no-inline-assembly */
        assembly {
            // check number of bytes returned from last function call
            switch returndatasize

            // no bytes returned: assume success
            case 0x0 {
                returnValue := 1
            }

            // 32 bytes returned: check if non-zero
            case 0x20 {
                // copy 32 bytes into scratch space
                returndatacopy(0x0, 0x0, 0x20)

                // load those bytes into returnValue
                returnValue := mload(0x0)
            }

            // not sure what was returned: don't mark as success
            default { }
        }

        return returnValue != 0;
    }
}

// File: contracts/protocol/interfaces/IInterestSetter.sol

/**
 * @title IInterestSetter
 * @author dYdX
 *
 * Interface that Interest Setters for Solo must implement in order to report interest rates.
 */
interface IInterestSetter {

    // ============ Public Functions ============

    /**
     * Get the interest rate of a token given some borrowed and supplied amounts
     *
     * @param  token        The address of the ERC20 token for the market
     * @param  borrowWei    The total borrowed token amount for the market
     * @param  supplyWei    The total supplied token amount for the market
     * @return              The interest rate per second
     */
    function getInterestRate(
        address token,
        uint256 borrowWei,
        uint256 supplyWei
    )
        external
        view
        returns (Interest.Rate memory);
}

// File: contracts/protocol/interfaces/IPriceOracle.sol

/**
 * @title IPriceOracle
 * @author dYdX
 *
 * Interface that Price Oracles for Solo must implement in order to report prices.
 */
contract IPriceOracle {

    // ============ Constants ============

    uint256 public constant ONE_DOLLAR = 10 ** 36;

    // ============ Public Functions ============

    /**
     * Get the price of a token
     *
     * @param  token  The ERC20 token address of the market
     * @return        The USD price of a base unit of the token, then multiplied by 10^36.
     *                So a USD-stable coin with 18 decimal places would return 10^18.
     *                This is the price of the base unit rather than the price of a "human-readable"
     *                token amount. Every ERC20 may have a different number of decimals.
     */
    function getPrice(
        address token
    )
        public
        view
        returns (Monetary.Price memory);
}

// File: contracts/protocol/lib/Storage.sol

/**
 * @title Storage
 * @author dYdX
 *
 * Functions for reading, writing, and verifying state in Solo
 */
library Storage {
    using Cache for Cache.MarketCache;
    using Storage for Storage.State;
    using Math for uint256;
    using Types for Types.Par;
    using Types for Types.Wei;
    using SafeMath for uint256;

    // ============ Constants ============

    bytes32 constant FILE = "Storage";

    // ============ Structs ============

    // All information necessary for tracking a market
    struct Market {
        // Contract address of the associated ERC20 token
        address token;

        // Total aggregated supply and borrow amount of the entire market
        Types.TotalPar totalPar;

        // Interest index of the market
        Interest.Index index;

        // Contract address of the price oracle for this market
        IPriceOracle priceOracle;

        // Contract address of the interest setter for this market
        IInterestSetter interestSetter;

        // Multiplier on the marginRatio for this market
        Decimal.D256 marginPremium;

        // Multiplier on the liquidationSpread for this market
        Decimal.D256 spreadPremium;

        // Whether additional borrows are allowed for this market
        bool isClosing;
    }

    // The global risk parameters that govern the health and security of the system
    struct RiskParams {
        // Required ratio of over-collateralization
        Decimal.D256 marginRatio;

        // Percentage penalty incurred by liquidated accounts
        Decimal.D256 liquidationSpread;

        // Percentage of the borrower's interest fee that gets passed to the suppliers
        Decimal.D256 earningsRate;

        // The minimum absolute borrow value of an account
        // There must be sufficient incentivize to liquidate undercollateralized accounts
        Monetary.Value minBorrowedValue;
    }

    // The maximum RiskParam values that can be set
    struct RiskLimits {
        uint64 marginRatioMax;
        uint64 liquidationSpreadMax;
        uint64 earningsRateMax;
        uint64 marginPremiumMax;
        uint64 spreadPremiumMax;
        uint128 minBorrowedValueMax;
    }

    // The entire storage state of Solo
    struct State {
        // number of markets
        uint256 numMarkets;

        // marketId => Market
        mapping (uint256 => Market) markets;

        // owner => account number => Account
        mapping (address => mapping (uint256 => Account.Storage)) accounts;

        // Addresses that can control other users accounts
        mapping (address => mapping (address => bool)) operators;

        // Addresses that can control all users accounts
        mapping (address => bool) globalOperators;

        // mutable risk parameters of the system
        RiskParams riskParams;

        // immutable risk limits of the system
        RiskLimits riskLimits;
    }

    // ============ Functions ============

    function getToken(
        Storage.State storage state,
        uint256 marketId
    )
        internal
        view
        returns (address)
    {
        return state.markets[marketId].token;
    }

    function getTotalPar(
        Storage.State storage state,
        uint256 marketId
    )
        internal
        view
        returns (Types.TotalPar memory)
    {
        return state.markets[marketId].totalPar;
    }

    function getIndex(
        Storage.State storage state,
        uint256 marketId
    )
        internal
        view
        returns (Interest.Index memory)
    {
        return state.markets[marketId].index;
    }

    function getNumExcessTokens(
        Storage.State storage state,
        uint256 marketId
    )
        internal
        view
        returns (Types.Wei memory)
    {
        Interest.Index memory index = state.getIndex(marketId);
        Types.TotalPar memory totalPar = state.getTotalPar(marketId);

        address token = state.getToken(marketId);

        Types.Wei memory balanceWei = Types.Wei({
            sign: true,
            value: Token.balanceOf(token, address(this))
        });

        (
            Types.Wei memory supplyWei,
            Types.Wei memory borrowWei
        ) = Interest.totalParToWei(totalPar, index);

        // borrowWei is negative, so subtracting it makes the value more positive
        return balanceWei.sub(borrowWei).sub(supplyWei);
    }

    function getStatus(
        Storage.State storage state,
        Account.Info memory account
    )
        internal
        view
        returns (Account.Status)
    {
        return state.accounts[account.owner][account.number].status;
    }

    function getPar(
        Storage.State storage state,
        Account.Info memory account,
        uint256 marketId
    )
        internal
        view
        returns (Types.Par memory)
    {
        return state.accounts[account.owner][account.number].balances[marketId];
    }

    function getWei(
        Storage.State storage state,
        Account.Info memory account,
        uint256 marketId
    )
        internal
        view
        returns (Types.Wei memory)
    {
        Types.Par memory par = state.getPar(account, marketId);

        if (par.isZero()) {
            return Types.zeroWei();
        }

        Interest.Index memory index = state.getIndex(marketId);
        return Interest.parToWei(par, index);
    }

    function getLiquidationSpreadForPair(
        Storage.State storage state,
        uint256 heldMarketId,
        uint256 owedMarketId
    )
        internal
        view
        returns (Decimal.D256 memory)
    {
        uint256 result = state.riskParams.liquidationSpread.value;
        result = Decimal.mul(result, Decimal.onePlus(state.markets[heldMarketId].spreadPremium));
        result = Decimal.mul(result, Decimal.onePlus(state.markets[owedMarketId].spreadPremium));
        return Decimal.D256({
            value: result
        });
    }

    function fetchNewIndex(
        Storage.State storage state,
        uint256 marketId,
        Interest.Index memory index
    )
        internal
        view
        returns (Interest.Index memory)
    {
        Interest.Rate memory rate = state.fetchInterestRate(marketId, index);

        return Interest.calculateNewIndex(
            index,
            rate,
            state.getTotalPar(marketId),
            state.riskParams.earningsRate
        );
    }

    function fetchInterestRate(
        Storage.State storage state,
        uint256 marketId,
        Interest.Index memory index
    )
        internal
        view
        returns (Interest.Rate memory)
    {
        Types.TotalPar memory totalPar = state.getTotalPar(marketId);
        (
            Types.Wei memory supplyWei,
            Types.Wei memory borrowWei
        ) = Interest.totalParToWei(totalPar, index);

        Interest.Rate memory rate = state.markets[marketId].interestSetter.getInterestRate(
            state.getToken(marketId),
            borrowWei.value,
            supplyWei.value
        );

        return rate;
    }

    function fetchPrice(
        Storage.State storage state,
        uint256 marketId
    )
        internal
        view
        returns (Monetary.Price memory)
    {
        IPriceOracle oracle = IPriceOracle(state.markets[marketId].priceOracle);
        Monetary.Price memory price = oracle.getPrice(state.getToken(marketId));
        Require.that(
            price.value != 0,
            FILE,
            "Price cannot be zero",
            marketId
        );
        return price;
    }

    function getAccountValues(
        Storage.State storage state,
        Account.Info memory account,
        Cache.MarketCache memory cache,
        bool adjustForLiquidity
    )
        internal
        view
        returns (Monetary.Value memory, Monetary.Value memory)
    {
        Monetary.Value memory supplyValue;
        Monetary.Value memory borrowValue;

        uint256 numMarkets = cache.getNumMarkets();
        for (uint256 m = 0; m < numMarkets; m++) {
            if (!cache.hasMarket(m)) {
                continue;
            }

            Types.Wei memory userWei = state.getWei(account, m);

            if (userWei.isZero()) {
                continue;
            }

            uint256 assetValue = userWei.value.mul(cache.getPrice(m).value);
            Decimal.D256 memory adjust = Decimal.one();
            if (adjustForLiquidity) {
                adjust = Decimal.onePlus(state.markets[m].marginPremium);
            }

            if (userWei.sign) {
                supplyValue.value = supplyValue.value.add(Decimal.div(assetValue, adjust));
            } else {
                borrowValue.value = borrowValue.value.add(Decimal.mul(assetValue, adjust));
            }
        }

        return (supplyValue, borrowValue);
    }

    function isCollateralized(
        Storage.State storage state,
        Account.Info memory account,
        Cache.MarketCache memory cache,
        bool requireMinBorrow
    )
        internal
        view
        returns (bool)
    {
        // get account values (adjusted for liquidity)
        (
            Monetary.Value memory supplyValue,
            Monetary.Value memory borrowValue
        ) = state.getAccountValues(account, cache, /* adjustForLiquidity = */ true);

        if (borrowValue.value == 0) {
            return true;
        }

        if (requireMinBorrow) {
            Require.that(
                borrowValue.value >= state.riskParams.minBorrowedValue.value,
                FILE,
                "Borrow value too low",
                account.owner,
                account.number,
                borrowValue.value
            );
        }

        uint256 requiredMargin = Decimal.mul(borrowValue.value, state.riskParams.marginRatio);

        return supplyValue.value >= borrowValue.value.add(requiredMargin);
    }

    function isGlobalOperator(
        Storage.State storage state,
        address operator
    )
        internal
        view
        returns (bool)
    {
        return state.globalOperators[operator];
    }

    function isLocalOperator(
        Storage.State storage state,
        address owner,
        address operator
    )
        internal
        view
        returns (bool)
    {
        return state.operators[owner][operator];
    }

    function requireIsOperator(
        Storage.State storage state,
        Account.Info memory account,
        address operator
    )
        internal
        view
    {
        bool isValidOperator =
            operator == account.owner
            || state.isGlobalOperator(operator)
            || state.isLocalOperator(account.owner, operator);

        Require.that(
            isValidOperator,
            FILE,
            "Unpermissioned operator",
            operator
        );
    }

    /**
     * Determine and set an account's balance based on the intended balance change. Return the
     * equivalent amount in wei
     */
    function getNewParAndDeltaWei(
        Storage.State storage state,
        Account.Info memory account,
        uint256 marketId,
        Types.AssetAmount memory amount
    )
        internal
        view
        returns (Types.Par memory, Types.Wei memory)
    {
        Types.Par memory oldPar = state.getPar(account, marketId);

        if (amount.value == 0 && amount.ref == Types.AssetReference.Delta) {
            return (oldPar, Types.zeroWei());
        }

        Interest.Index memory index = state.getIndex(marketId);
        Types.Wei memory oldWei = Interest.parToWei(oldPar, index);
        Types.Par memory newPar;
        Types.Wei memory deltaWei;

        if (amount.denomination == Types.AssetDenomination.Wei) {
            deltaWei = Types.Wei({
                sign: amount.sign,
                value: amount.value
            });
            if (amount.ref == Types.AssetReference.Target) {
                deltaWei = deltaWei.sub(oldWei);
            }
            newPar = Interest.weiToPar(oldWei.add(deltaWei), index);
        } else { // AssetDenomination.Par
            newPar = Types.Par({
                sign: amount.sign,
                value: amount.value.to128()
            });
            if (amount.ref == Types.AssetReference.Delta) {
                newPar = oldPar.add(newPar);
            }
            deltaWei = Interest.parToWei(newPar, index).sub(oldWei);
        }

        return (newPar, deltaWei);
    }

    function getNewParAndDeltaWeiForLiquidation(
        Storage.State storage state,
        Account.Info memory account,
        uint256 marketId,
        Types.AssetAmount memory amount
    )
        internal
        view
        returns (Types.Par memory, Types.Wei memory)
    {
        Types.Par memory oldPar = state.getPar(account, marketId);

        Require.that(
            !oldPar.isPositive(),
            FILE,
            "Owed balance cannot be positive",
            account.owner,
            account.number,
            marketId
        );

        (
            Types.Par memory newPar,
            Types.Wei memory deltaWei
        ) = state.getNewParAndDeltaWei(
            account,
            marketId,
            amount
        );

        // if attempting to over-repay the owed asset, bound it by the maximum
        if (newPar.isPositive()) {
            newPar = Types.zeroPar();
            deltaWei = state.getWei(account, marketId).negative();
        }

        Require.that(
            !deltaWei.isNegative() && oldPar.value >= newPar.value,
            FILE,
            "Owed balance cannot increase",
            account.owner,
            account.number,
            marketId
        );

        // if not paying back enough wei to repay any par, then bound wei to zero
        if (oldPar.equals(newPar)) {
            deltaWei = Types.zeroWei();
        }

        return (newPar, deltaWei);
    }

    function isVaporizable(
        Storage.State storage state,
        Account.Info memory account,
        Cache.MarketCache memory cache
    )
        internal
        view
        returns (bool)
    {
        bool hasNegative = false;
        uint256 numMarkets = cache.getNumMarkets();
        for (uint256 m = 0; m < numMarkets; m++) {
            if (!cache.hasMarket(m)) {
                continue;
            }
            Types.Par memory par = state.getPar(account, m);
            if (par.isZero()) {
                continue;
            } else if (par.sign) {
                return false;
            } else {
                hasNegative = true;
            }
        }
        return hasNegative;
    }

    // =============== Setter Functions ===============

    function updateIndex(
        Storage.State storage state,
        uint256 marketId
    )
        internal
        returns (Interest.Index memory)
    {
        Interest.Index memory index = state.getIndex(marketId);
        if (index.lastUpdate == Time.currentTime()) {
            return index;
        }
        return state.markets[marketId].index = state.fetchNewIndex(marketId, index);
    }

    function setStatus(
        Storage.State storage state,
        Account.Info memory account,
        Account.Status status
    )
        internal
    {
        state.accounts[account.owner][account.number].status = status;
    }

    function setPar(
        Storage.State storage state,
        Account.Info memory account,
        uint256 marketId,
        Types.Par memory newPar
    )
        internal
    {
        Types.Par memory oldPar = state.getPar(account, marketId);

        if (Types.equals(oldPar, newPar)) {
            return;
        }

        // updateTotalPar
        Types.TotalPar memory totalPar = state.getTotalPar(marketId);

        // roll-back oldPar
        if (oldPar.sign) {
            totalPar.supply = uint256(totalPar.supply).sub(oldPar.value).to128();
        } else {
            totalPar.borrow = uint256(totalPar.borrow).sub(oldPar.value).to128();
        }

        // roll-forward newPar
        if (newPar.sign) {
            totalPar.supply = uint256(totalPar.supply).add(newPar.value).to128();
        } else {
            totalPar.borrow = uint256(totalPar.borrow).add(newPar.value).to128();
        }

        state.markets[marketId].totalPar = totalPar;
        state.accounts[account.owner][account.number].balances[marketId] = newPar;
    }

    /**
     * Determine and set an account's balance based on a change in wei
     */
    function setParFromDeltaWei(
        Storage.State storage state,
        Account.Info memory account,
        uint256 marketId,
        Types.Wei memory deltaWei
    )
        internal
    {
        if (deltaWei.isZero()) {
            return;
        }
        Interest.Index memory index = state.getIndex(marketId);
        Types.Wei memory oldWei = state.getWei(account, marketId);
        Types.Wei memory newWei = oldWei.add(deltaWei);
        Types.Par memory newPar = Interest.weiToPar(newWei, index);
        state.setPar(
            account,
            marketId,
            newPar
        );
    }
}

// File: contracts/protocol/lib/Events.sol

/**
 * @title Events
 * @author dYdX
 *
 * Library to parse and emit logs from which the state of all accounts and indexes can be followed
 */
library Events {
    using Types for Types.Wei;
    using Storage for Storage.State;

    // ============ Events ============

    event LogIndexUpdate(
        uint256 indexed market,
        Interest.Index index
    );

    event LogOperation(
        address sender
    );

    event LogDeposit(
        address indexed accountOwner,
        uint256 accountNumber,
        uint256 market,
        BalanceUpdate update,
        address from
    );

    event LogWithdraw(
        address indexed accountOwner,
        uint256 accountNumber,
        uint256 market,
        BalanceUpdate update,
        address to
    );

    event LogTransfer(
        address indexed accountOneOwner,
        uint256 accountOneNumber,
        address indexed accountTwoOwner,
        uint256 accountTwoNumber,
        uint256 market,
        BalanceUpdate updateOne,
        BalanceUpdate updateTwo
    );

    event LogBuy(
        address indexed accountOwner,
        uint256 accountNumber,
        uint256 takerMarket,
        uint256 makerMarket,
        BalanceUpdate takerUpdate,
        BalanceUpdate makerUpdate,
        address exchangeWrapper
    );

    event LogSell(
        address indexed accountOwner,
        uint256 accountNumber,
        uint256 takerMarket,
        uint256 makerMarket,
        BalanceUpdate takerUpdate,
        BalanceUpdate makerUpdate,
        address exchangeWrapper
    );

    event LogTrade(
        address indexed takerAccountOwner,
        uint256 takerAccountNumber,
        address indexed makerAccountOwner,
        uint256 makerAccountNumber,
        uint256 inputMarket,
        uint256 outputMarket,
        BalanceUpdate takerInputUpdate,
        BalanceUpdate takerOutputUpdate,
        BalanceUpdate makerInputUpdate,
        BalanceUpdate makerOutputUpdate,
        address autoTrader
    );

    event LogCall(
        address indexed accountOwner,
        uint256 accountNumber,
        address callee
    );

    event LogLiquidate(
        address indexed solidAccountOwner,
        uint256 solidAccountNumber,
        address indexed liquidAccountOwner,
        uint256 liquidAccountNumber,
        uint256 heldMarket,
        uint256 owedMarket,
        BalanceUpdate solidHeldUpdate,
        BalanceUpdate solidOwedUpdate,
        BalanceUpdate liquidHeldUpdate,
        BalanceUpdate liquidOwedUpdate
    );

    event LogVaporize(
        address indexed solidAccountOwner,
        uint256 solidAccountNumber,
        address indexed vaporAccountOwner,
        uint256 vaporAccountNumber,
        uint256 heldMarket,
        uint256 owedMarket,
        BalanceUpdate solidHeldUpdate,
        BalanceUpdate solidOwedUpdate,
        BalanceUpdate vaporOwedUpdate
    );

    // ============ Structs ============

    struct BalanceUpdate {
        Types.Wei deltaWei;
        Types.Par newPar;
    }

    // ============ Internal Functions ============

    function logIndexUpdate(
        uint256 marketId,
        Interest.Index memory index
    )
        internal
    {
        emit LogIndexUpdate(
            marketId,
            index
        );
    }

    function logOperation()
        internal
    {
        emit LogOperation(msg.sender);
    }

    function logDeposit(
        Storage.State storage state,
        Actions.DepositArgs memory args,
        Types.Wei memory deltaWei
    )
        internal
    {
        emit LogDeposit(
            args.account.owner,
            args.account.number,
            args.market,
            getBalanceUpdate(
                state,
                args.account,
                args.market,
                deltaWei
            ),
            args.from
        );
    }

    function logWithdraw(
        Storage.State storage state,
        Actions.WithdrawArgs memory args,
        Types.Wei memory deltaWei
    )
        internal
    {
        emit LogWithdraw(
            args.account.owner,
            args.account.number,
            args.market,
            getBalanceUpdate(
                state,
                args.account,
                args.market,
                deltaWei
            ),
            args.to
        );
    }

    function logTransfer(
        Storage.State storage state,
        Actions.TransferArgs memory args,
        Types.Wei memory deltaWei
    )
        internal
    {
        emit LogTransfer(
            args.accountOne.owner,
            args.accountOne.number,
            args.accountTwo.owner,
            args.accountTwo.number,
            args.market,
            getBalanceUpdate(
                state,
                args.accountOne,
                args.market,
                deltaWei
            ),
            getBalanceUpdate(
                state,
                args.accountTwo,
                args.market,
                deltaWei.negative()
            )
        );
    }

    function logBuy(
        Storage.State storage state,
        Actions.BuyArgs memory args,
        Types.Wei memory takerWei,
        Types.Wei memory makerWei
    )
        internal
    {
        emit LogBuy(
            args.account.owner,
            args.account.number,
            args.takerMarket,
            args.makerMarket,
            getBalanceUpdate(
                state,
                args.account,
                args.takerMarket,
                takerWei
            ),
            getBalanceUpdate(
                state,
                args.account,
                args.makerMarket,
                makerWei
            ),
            args.exchangeWrapper
        );
    }

    function logSell(
        Storage.State storage state,
        Actions.SellArgs memory args,
        Types.Wei memory takerWei,
        Types.Wei memory makerWei
    )
        internal
    {
        emit LogSell(
            args.account.owner,
            args.account.number,
            args.takerMarket,
            args.makerMarket,
            getBalanceUpdate(
                state,
                args.account,
                args.takerMarket,
                takerWei
            ),
            getBalanceUpdate(
                state,
                args.account,
                args.makerMarket,
                makerWei
            ),
            args.exchangeWrapper
        );
    }

    function logTrade(
        Storage.State storage state,
        Actions.TradeArgs memory args,
        Types.Wei memory inputWei,
        Types.Wei memory outputWei
    )
        internal
    {
        BalanceUpdate[4] memory updates = [
            getBalanceUpdate(
                state,
                args.takerAccount,
                args.inputMarket,
                inputWei.negative()
            ),
            getBalanceUpdate(
                state,
                args.takerAccount,
                args.outputMarket,
                outputWei.negative()
            ),
            getBalanceUpdate(
                state,
                args.makerAccount,
                args.inputMarket,
                inputWei
            ),
            getBalanceUpdate(
                state,
                args.makerAccount,
                args.outputMarket,
                outputWei
            )
        ];

        emit LogTrade(
            args.takerAccount.owner,
            args.takerAccount.number,
            args.makerAccount.owner,
            args.makerAccount.number,
            args.inputMarket,
            args.outputMarket,
            updates[0],
            updates[1],
            updates[2],
            updates[3],
            args.autoTrader
        );
    }

    function logCall(
        Actions.CallArgs memory args
    )
        internal
    {
        emit LogCall(
            args.account.owner,
            args.account.number,
            args.callee
        );
    }

    function logLiquidate(
        Storage.State storage state,
        Actions.LiquidateArgs memory args,
        Types.Wei memory heldWei,
        Types.Wei memory owedWei
    )
        internal
    {
        BalanceUpdate memory solidHeldUpdate = getBalanceUpdate(
            state,
            args.solidAccount,
            args.heldMarket,
            heldWei.negative()
        );
        BalanceUpdate memory solidOwedUpdate = getBalanceUpdate(
            state,
            args.solidAccount,
            args.owedMarket,
            owedWei.negative()
        );
        BalanceUpdate memory liquidHeldUpdate = getBalanceUpdate(
            state,
            args.liquidAccount,
            args.heldMarket,
            heldWei
        );
        BalanceUpdate memory liquidOwedUpdate = getBalanceUpdate(
            state,
            args.liquidAccount,
            args.owedMarket,
            owedWei
        );

        emit LogLiquidate(
            args.solidAccount.owner,
            args.solidAccount.number,
            args.liquidAccount.owner,
            args.liquidAccount.number,
            args.heldMarket,
            args.owedMarket,
            solidHeldUpdate,
            solidOwedUpdate,
            liquidHeldUpdate,
            liquidOwedUpdate
        );
    }

    function logVaporize(
        Storage.State storage state,
        Actions.VaporizeArgs memory args,
        Types.Wei memory heldWei,
        Types.Wei memory owedWei,
        Types.Wei memory excessWei
    )
        internal
    {
        BalanceUpdate memory solidHeldUpdate = getBalanceUpdate(
            state,
            args.solidAccount,
            args.heldMarket,
            heldWei.negative()
        );
        BalanceUpdate memory solidOwedUpdate = getBalanceUpdate(
            state,
            args.solidAccount,
            args.owedMarket,
            owedWei.negative()
        );
        BalanceUpdate memory vaporOwedUpdate = getBalanceUpdate(
            state,
            args.vaporAccount,
            args.owedMarket,
            owedWei.add(excessWei)
        );

        emit LogVaporize(
            args.solidAccount.owner,
            args.solidAccount.number,
            args.vaporAccount.owner,
            args.vaporAccount.number,
            args.heldMarket,
            args.owedMarket,
            solidHeldUpdate,
            solidOwedUpdate,
            vaporOwedUpdate
        );
    }

    // ============ Private Functions ============

    function getBalanceUpdate(
        Storage.State storage state,
        Account.Info memory account,
        uint256 market,
        Types.Wei memory deltaWei
    )
        private
        view
        returns (BalanceUpdate memory)
    {
        return BalanceUpdate({
            deltaWei: deltaWei,
            newPar: state.getPar(account, market)
        });
    }
}

// File: contracts/protocol/interfaces/IExchangeWrapper.sol

/**
 * @title IExchangeWrapper
 * @author dYdX
 *
 * Interface that Exchange Wrappers for Solo must implement in order to trade ERC20 tokens.
 */
interface IExchangeWrapper {

    // ============ Public Functions ============

    /**
     * Exchange some amount of takerToken for makerToken.
     *
     * @param  tradeOriginator      Address of the initiator of the trade (however, this value
     *                              cannot always be trusted as it is set at the discretion of the
     *                              msg.sender)
     * @param  receiver             Address to set allowance on once the trade has completed
     * @param  makerToken           Address of makerToken, the token to receive
     * @param  takerToken           Address of takerToken, the token to pay
     * @param  requestedFillAmount  Amount of takerToken being paid
     * @param  orderData            Arbitrary bytes data for any information to pass to the exchange
     * @return                      The amount of makerToken received
     */
    function exchange(
        address tradeOriginator,
        address receiver,
        address makerToken,
        address takerToken,
        uint256 requestedFillAmount,
        bytes calldata orderData
    )
        external
        returns (uint256);

    /**
     * Get amount of takerToken required to buy a certain amount of makerToken for a given trade.
     * Should match the takerToken amount used in exchangeForAmount. If the order cannot provide
     * exactly desiredMakerToken, then it must return the price to buy the minimum amount greater
     * than desiredMakerToken
     *
     * @param  makerToken         Address of makerToken, the token to receive
     * @param  takerToken         Address of takerToken, the token to pay
     * @param  desiredMakerToken  Amount of makerToken requested
     * @param  orderData          Arbitrary bytes data for any information to pass to the exchange
     * @return                    Amount of takerToken the needed to complete the exchange
     */
    function getExchangeCost(
        address makerToken,
        address takerToken,
        uint256 desiredMakerToken,
        bytes calldata orderData
    )
        external
        view
        returns (uint256);
}

// File: contracts/protocol/lib/Exchange.sol

/**
 * @title Exchange
 * @author dYdX
 *
 * Library for transferring tokens and interacting with ExchangeWrappers by using the Wei struct
 */
library Exchange {
    using Types for Types.Wei;

    // ============ Constants ============

    bytes32 constant FILE = "Exchange";

    // ============ Library Functions ============

    function transferOut(
        address token,
        address to,
        Types.Wei memory deltaWei
    )
        internal
    {
        Require.that(
            !deltaWei.isPositive(),
            FILE,
            "Cannot transferOut positive",
            deltaWei.value
        );

        Token.transfer(
            token,
            to,
            deltaWei.value
        );
    }

    function transferIn(
        address token,
        address from,
        Types.Wei memory deltaWei
    )
        internal
    {
        Require.that(
            !deltaWei.isNegative(),
            FILE,
            "Cannot transferIn negative",
            deltaWei.value
        );

        Token.transferFrom(
            token,
            from,
            address(this),
            deltaWei.value
        );
    }

    function getCost(
        address exchangeWrapper,
        address supplyToken,
        address borrowToken,
        Types.Wei memory desiredAmount,
        bytes memory orderData
    )
        internal
        view
        returns (Types.Wei memory)
    {
        Require.that(
            !desiredAmount.isNegative(),
            FILE,
            "Cannot getCost negative",
            desiredAmount.value
        );

        Types.Wei memory result;
        result.sign = false;
        result.value = IExchangeWrapper(exchangeWrapper).getExchangeCost(
            supplyToken,
            borrowToken,
            desiredAmount.value,
            orderData
        );

        return result;
    }

    function exchange(
        address exchangeWrapper,
        address accountOwner,
        address supplyToken,
        address borrowToken,
        Types.Wei memory requestedFillAmount,
        bytes memory orderData
    )
        internal
        returns (Types.Wei memory)
    {
        Require.that(
            !requestedFillAmount.isPositive(),
            FILE,
            "Cannot exchange positive",
            requestedFillAmount.value
        );

        transferOut(borrowToken, exchangeWrapper, requestedFillAmount);

        Types.Wei memory result;
        result.sign = true;
        result.value = IExchangeWrapper(exchangeWrapper).exchange(
            accountOwner,
            address(this),
            supplyToken,
            borrowToken,
            requestedFillAmount.value,
            orderData
        );

        transferIn(supplyToken, exchangeWrapper, result);

        return result;
    }
}

// File: contracts/protocol/impl/OperationImpl.sol

/**
 * @title OperationImpl
 * @author dYdX
 *
 * Logic for processing actions
 */
library OperationImpl {
    using Cache for Cache.MarketCache;
    using SafeMath for uint256;
    using Storage for Storage.State;
    using Types for Types.Par;
    using Types for Types.Wei;

    // ============ Constants ============

    bytes32 constant FILE = "OperationImpl";

    // ============ Public Functions ============

    function operate(
        Storage.State storage state,
        Account.Info[] memory accounts,
        Actions.ActionArgs[] memory actions
    )
        public
    {
        Events.logOperation();

        _verifyInputs(accounts, actions);

        (
            bool[] memory primaryAccounts,
            Cache.MarketCache memory cache
        ) = _runPreprocessing(
            state,
            accounts,
            actions
        );

        _runActions(
            state,
            accounts,
            actions,
            cache
        );

        _verifyFinalState(
            state,
            accounts,
            primaryAccounts,
            cache
        );
    }

    // ============ Helper Functions ============

    function _verifyInputs(
        Account.Info[] memory accounts,
        Actions.ActionArgs[] memory actions
    )
        private
        pure
    {
        Require.that(
            actions.length != 0,
            FILE,
            "Cannot have zero actions"
        );

        Require.that(
            accounts.length != 0,
            FILE,
            "Cannot have zero accounts"
        );

        for (uint256 a = 0; a < accounts.length; a++) {
            for (uint256 b = a + 1; b < accounts.length; b++) {
                Require.that(
                    !Account.equals(accounts[a], accounts[b]),
                    FILE,
                    "Cannot duplicate accounts",
                    a,
                    b
                );
            }
        }
    }

    function _runPreprocessing(
        Storage.State storage state,
        Account.Info[] memory accounts,
        Actions.ActionArgs[] memory actions
    )
        private
        returns (
            bool[] memory,
            Cache.MarketCache memory
        )
    {
        uint256 numMarkets = state.numMarkets;
        bool[] memory primaryAccounts = new bool[](accounts.length);
        Cache.MarketCache memory cache = Cache.create(numMarkets);

        // keep track of primary accounts and indexes that need updating
        for (uint256 i = 0; i < actions.length; i++) {
            Actions.ActionArgs memory arg = actions[i];
            Actions.ActionType actionType = arg.actionType;
            Actions.MarketLayout marketLayout = Actions.getMarketLayout(actionType);
            Actions.AccountLayout accountLayout = Actions.getAccountLayout(actionType);

            // parse out primary accounts
            if (accountLayout != Actions.AccountLayout.OnePrimary) {
                Require.that(
                    arg.accountId != arg.otherAccountId,
                    FILE,
                    "Duplicate accounts in action",
                    i
                );
                if (accountLayout == Actions.AccountLayout.TwoPrimary) {
                    primaryAccounts[arg.otherAccountId] = true;
                } else {
                    assert(accountLayout == Actions.AccountLayout.PrimaryAndSecondary);
                    Require.that(
                        !primaryAccounts[arg.otherAccountId],
                        FILE,
                        "Requires non-primary account",
                        arg.otherAccountId
                    );
                }
            }
            primaryAccounts[arg.accountId] = true;

            // keep track of indexes to update
            if (marketLayout == Actions.MarketLayout.OneMarket) {
                _updateMarket(state, cache, arg.primaryMarketId);
            } else if (marketLayout == Actions.MarketLayout.TwoMarkets) {
                Require.that(
                    arg.primaryMarketId != arg.secondaryMarketId,
                    FILE,
                    "Duplicate markets in action",
                    i
                );
                _updateMarket(state, cache, arg.primaryMarketId);
                _updateMarket(state, cache, arg.secondaryMarketId);
            } else {
                assert(marketLayout == Actions.MarketLayout.ZeroMarkets);
            }
        }

        // get any other markets for which an account has a balance
        for (uint256 m = 0; m < numMarkets; m++) {
            if (cache.hasMarket(m)) {
                continue;
            }
            for (uint256 a = 0; a < accounts.length; a++) {
                if (!state.getPar(accounts[a], m).isZero()) {
                    _updateMarket(state, cache, m);
                    break;
                }
            }
        }

        return (primaryAccounts, cache);
    }

    function _updateMarket(
        Storage.State storage state,
        Cache.MarketCache memory cache,
        uint256 marketId
    )
        private
    {
        bool updated = cache.addMarket(state, marketId);
        if (updated) {
            Events.logIndexUpdate(marketId, state.updateIndex(marketId));
        }
    }

    function _runActions(
        Storage.State storage state,
        Account.Info[] memory accounts,
        Actions.ActionArgs[] memory actions,
        Cache.MarketCache memory cache
    )
        private
    {
        for (uint256 i = 0; i < actions.length; i++) {
            Actions.ActionArgs memory action = actions[i];
            Actions.ActionType actionType = action.actionType;

            if (actionType == Actions.ActionType.Deposit) {
                _deposit(state, Actions.parseDepositArgs(accounts, action));
            }
            else if (actionType == Actions.ActionType.Withdraw) {
                _withdraw(state, Actions.parseWithdrawArgs(accounts, action));
            }
            else if (actionType == Actions.ActionType.Transfer) {
                _transfer(state, Actions.parseTransferArgs(accounts, action));
            }
            else if (actionType == Actions.ActionType.Buy) {
                _buy(state, Actions.parseBuyArgs(accounts, action));
            }
            else if (actionType == Actions.ActionType.Sell) {
                _sell(state, Actions.parseSellArgs(accounts, action));
            }
            else if (actionType == Actions.ActionType.Trade) {
                _trade(state, Actions.parseTradeArgs(accounts, action));
            }
            else if (actionType == Actions.ActionType.Liquidate) {
                _liquidate(state, Actions.parseLiquidateArgs(accounts, action), cache);
            }
            else if (actionType == Actions.ActionType.Vaporize) {
                _vaporize(state, Actions.parseVaporizeArgs(accounts, action), cache);
            }
            else  {
                assert(actionType == Actions.ActionType.Call);
                _call(state, Actions.parseCallArgs(accounts, action));
            }
        }
    }

    function _verifyFinalState(
        Storage.State storage state,
        Account.Info[] memory accounts,
        bool[] memory primaryAccounts,
        Cache.MarketCache memory cache
    )
        private
    {
        // verify no increase in borrowPar for closing markets
        uint256 numMarkets = cache.getNumMarkets();
        for (uint256 m = 0; m < numMarkets; m++) {
            if (cache.getIsClosing(m)) {
                Require.that(
                    state.getTotalPar(m).borrow <= cache.getBorrowPar(m),
                    FILE,
                    "Market is closing",
                    m
                );
            }
        }

        // verify account collateralization
        for (uint256 a = 0; a < accounts.length; a++) {
            Account.Info memory account = accounts[a];

            // validate minBorrowedValue
            bool collateralized = state.isCollateralized(account, cache, true);

            // don't check collateralization for non-primary accounts
            if (!primaryAccounts[a]) {
                continue;
            }

            // check collateralization for primary accounts
            Require.that(
                collateralized,
                FILE,
                "Undercollateralized account",
                account.owner,
                account.number
            );

            // ensure status is normal for primary accounts
            if (state.getStatus(account) != Account.Status.Normal) {
                state.setStatus(account, Account.Status.Normal);
            }
        }
    }

    // ============ Action Functions ============

    function _deposit(
        Storage.State storage state,
        Actions.DepositArgs memory args
    )
        private
    {
        state.requireIsOperator(args.account, msg.sender);

        Require.that(
            args.from == msg.sender || args.from == args.account.owner,
            FILE,
            "Invalid deposit source",
            args.from
        );

        (
            Types.Par memory newPar,
            Types.Wei memory deltaWei
        ) = state.getNewParAndDeltaWei(
            args.account,
            args.market,
            args.amount
        );

        state.setPar(
            args.account,
            args.market,
            newPar
        );

        // requires a positive deltaWei
        Exchange.transferIn(
            state.getToken(args.market),
            args.from,
            deltaWei
        );

        Events.logDeposit(
            state,
            args,
            deltaWei
        );
    }

    function _withdraw(
        Storage.State storage state,
        Actions.WithdrawArgs memory args
    )
        private
    {
        state.requireIsOperator(args.account, msg.sender);

        (
            Types.Par memory newPar,
            Types.Wei memory deltaWei
        ) = state.getNewParAndDeltaWei(
            args.account,
            args.market,
            args.amount
        );

        state.setPar(
            args.account,
            args.market,
            newPar
        );

        // requires a negative deltaWei
        Exchange.transferOut(
            state.getToken(args.market),
            args.to,
            deltaWei
        );

        Events.logWithdraw(
            state,
            args,
            deltaWei
        );
    }

    function _transfer(
        Storage.State storage state,
        Actions.TransferArgs memory args
    )
        private
    {
        state.requireIsOperator(args.accountOne, msg.sender);
        state.requireIsOperator(args.accountTwo, msg.sender);

        (
            Types.Par memory newPar,
            Types.Wei memory deltaWei
        ) = state.getNewParAndDeltaWei(
            args.accountOne,
            args.market,
            args.amount
        );

        state.setPar(
            args.accountOne,
            args.market,
            newPar
        );

        state.setParFromDeltaWei(
            args.accountTwo,
            args.market,
            deltaWei.negative()
        );

        Events.logTransfer(
            state,
            args,
            deltaWei
        );
    }

    function _buy(
        Storage.State storage state,
        Actions.BuyArgs memory args
    )
        private
    {
        state.requireIsOperator(args.account, msg.sender);

        address takerToken = state.getToken(args.takerMarket);
        address makerToken = state.getToken(args.makerMarket);

        (
            Types.Par memory makerPar,
            Types.Wei memory makerWei
        ) = state.getNewParAndDeltaWei(
            args.account,
            args.makerMarket,
            args.amount
        );

        Types.Wei memory takerWei = Exchange.getCost(
            args.exchangeWrapper,
            makerToken,
            takerToken,
            makerWei,
            args.orderData
        );

        Types.Wei memory tokensReceived = Exchange.exchange(
            args.exchangeWrapper,
            args.account.owner,
            makerToken,
            takerToken,
            takerWei,
            args.orderData
        );

        Require.that(
            tokensReceived.value >= makerWei.value,
            FILE,
            "Buy amount less than promised",
            tokensReceived.value,
            makerWei.value
        );

        state.setPar(
            args.account,
            args.makerMarket,
            makerPar
        );

        state.setParFromDeltaWei(
            args.account,
            args.takerMarket,
            takerWei
        );

        Events.logBuy(
            state,
            args,
            takerWei,
            makerWei
        );
    }

    function _sell(
        Storage.State storage state,
        Actions.SellArgs memory args
    )
        private
    {
        state.requireIsOperator(args.account, msg.sender);

        address takerToken = state.getToken(args.takerMarket);
        address makerToken = state.getToken(args.makerMarket);

        (
            Types.Par memory takerPar,
            Types.Wei memory takerWei
        ) = state.getNewParAndDeltaWei(
            args.account,
            args.takerMarket,
            args.amount
        );

        Types.Wei memory makerWei = Exchange.exchange(
            args.exchangeWrapper,
            args.account.owner,
            makerToken,
            takerToken,
            takerWei,
            args.orderData
        );

        state.setPar(
            args.account,
            args.takerMarket,
            takerPar
        );

        state.setParFromDeltaWei(
            args.account,
            args.makerMarket,
            makerWei
        );

        Events.logSell(
            state,
            args,
            takerWei,
            makerWei
        );
    }

    function _trade(
        Storage.State storage state,
        Actions.TradeArgs memory args
    )
        private
    {
        state.requireIsOperator(args.takerAccount, msg.sender);
        state.requireIsOperator(args.makerAccount, args.autoTrader);

        Types.Par memory oldInputPar = state.getPar(
            args.makerAccount,
            args.inputMarket
        );
        (
            Types.Par memory newInputPar,
            Types.Wei memory inputWei
        ) = state.getNewParAndDeltaWei(
            args.makerAccount,
            args.inputMarket,
            args.amount
        );

        Types.AssetAmount memory outputAmount = IAutoTrader(args.autoTrader).getTradeCost(
            args.inputMarket,
            args.outputMarket,
            args.makerAccount,
            args.takerAccount,
            oldInputPar,
            newInputPar,
            inputWei,
            args.tradeData
        );

        (
            Types.Par memory newOutputPar,
            Types.Wei memory outputWei
        ) = state.getNewParAndDeltaWei(
            args.makerAccount,
            args.outputMarket,
            outputAmount
        );

        Require.that(
            outputWei.isZero() || inputWei.isZero() || outputWei.sign != inputWei.sign,
            FILE,
            "Trades cannot be one-sided"
        );

        // set the balance for the maker
        state.setPar(
            args.makerAccount,
            args.inputMarket,
            newInputPar
        );
        state.setPar(
            args.makerAccount,
            args.outputMarket,
            newOutputPar
        );

        // set the balance for the taker
        state.setParFromDeltaWei(
            args.takerAccount,
            args.inputMarket,
            inputWei.negative()
        );
        state.setParFromDeltaWei(
            args.takerAccount,
            args.outputMarket,
            outputWei.negative()
        );

        Events.logTrade(
            state,
            args,
            inputWei,
            outputWei
        );
    }

    function _liquidate(
        Storage.State storage state,
        Actions.LiquidateArgs memory args,
        Cache.MarketCache memory cache
    )
        private
    {
        state.requireIsOperator(args.solidAccount, msg.sender);

        // verify liquidatable
        if (Account.Status.Liquid != state.getStatus(args.liquidAccount)) {
            Require.that(
                !state.isCollateralized(args.liquidAccount, cache, /* requireMinBorrow = */ false),
                FILE,
                "Unliquidatable account",
                args.liquidAccount.owner,
                args.liquidAccount.number
            );
            state.setStatus(args.liquidAccount, Account.Status.Liquid);
        }

        Types.Wei memory maxHeldWei = state.getWei(
            args.liquidAccount,
            args.heldMarket
        );

        Require.that(
            !maxHeldWei.isNegative(),
            FILE,
            "Collateral cannot be negative",
            args.liquidAccount.owner,
            args.liquidAccount.number,
            args.heldMarket
        );

        (
            Types.Par memory owedPar,
            Types.Wei memory owedWei
        ) = state.getNewParAndDeltaWeiForLiquidation(
            args.liquidAccount,
            args.owedMarket,
            args.amount
        );

        (
            Monetary.Price memory heldPrice,
            Monetary.Price memory owedPrice
        ) = _getLiquidationPrices(
            state,
            cache,
            args.heldMarket,
            args.owedMarket
        );

        Types.Wei memory heldWei = _owedWeiToHeldWei(owedWei, heldPrice, owedPrice);

        // if attempting to over-borrow the held asset, bound it by the maximum
        if (heldWei.value > maxHeldWei.value) {
            heldWei = maxHeldWei.negative();
            owedWei = _heldWeiToOwedWei(heldWei, heldPrice, owedPrice);

            state.setPar(
                args.liquidAccount,
                args.heldMarket,
                Types.zeroPar()
            );
            state.setParFromDeltaWei(
                args.liquidAccount,
                args.owedMarket,
                owedWei
            );
        } else {
            state.setPar(
                args.liquidAccount,
                args.owedMarket,
                owedPar
            );
            state.setParFromDeltaWei(
                args.liquidAccount,
                args.heldMarket,
                heldWei
            );
        }

        // set the balances for the solid account
        state.setParFromDeltaWei(
            args.solidAccount,
            args.owedMarket,
            owedWei.negative()
        );
        state.setParFromDeltaWei(
            args.solidAccount,
            args.heldMarket,
            heldWei.negative()
        );

        Events.logLiquidate(
            state,
            args,
            heldWei,
            owedWei
        );
    }

    function _vaporize(
        Storage.State storage state,
        Actions.VaporizeArgs memory args,
        Cache.MarketCache memory cache
    )
        private
    {
        state.requireIsOperator(args.solidAccount, msg.sender);

        // verify vaporizable
        if (Account.Status.Vapor != state.getStatus(args.vaporAccount)) {
            Require.that(
                state.isVaporizable(args.vaporAccount, cache),
                FILE,
                "Unvaporizable account",
                args.vaporAccount.owner,
                args.vaporAccount.number
            );
            state.setStatus(args.vaporAccount, Account.Status.Vapor);
        }

        // First, attempt to refund using the same token
        (
            bool fullyRepaid,
            Types.Wei memory excessWei
        ) = _vaporizeUsingExcess(state, args);
        if (fullyRepaid) {
            Events.logVaporize(
                state,
                args,
                Types.zeroWei(),
                Types.zeroWei(),
                excessWei
            );
            return;
        }

        Types.Wei memory maxHeldWei = state.getNumExcessTokens(args.heldMarket);

        Require.that(
            !maxHeldWei.isNegative(),
            FILE,
            "Excess cannot be negative",
            args.heldMarket
        );

        (
            Types.Par memory owedPar,
            Types.Wei memory owedWei
        ) = state.getNewParAndDeltaWeiForLiquidation(
            args.vaporAccount,
            args.owedMarket,
            args.amount
        );

        (
            Monetary.Price memory heldPrice,
            Monetary.Price memory owedPrice
        ) = _getLiquidationPrices(
            state,
            cache,
            args.heldMarket,
            args.owedMarket
        );

        Types.Wei memory heldWei = _owedWeiToHeldWei(owedWei, heldPrice, owedPrice);

        // if attempting to over-borrow the held asset, bound it by the maximum
        if (heldWei.value > maxHeldWei.value) {
            heldWei = maxHeldWei.negative();
            owedWei = _heldWeiToOwedWei(heldWei, heldPrice, owedPrice);

            state.setParFromDeltaWei(
                args.vaporAccount,
                args.owedMarket,
                owedWei
            );
        } else {
            state.setPar(
                args.vaporAccount,
                args.owedMarket,
                owedPar
            );
        }

        // set the balances for the solid account
        state.setParFromDeltaWei(
            args.solidAccount,
            args.owedMarket,
            owedWei.negative()
        );
        state.setParFromDeltaWei(
            args.solidAccount,
            args.heldMarket,
            heldWei.negative()
        );

        Events.logVaporize(
            state,
            args,
            heldWei,
            owedWei,
            excessWei
        );
    }

    function _call(
        Storage.State storage state,
        Actions.CallArgs memory args
    )
        private
    {
        state.requireIsOperator(args.account, msg.sender);

        ICallee(args.callee).callFunction(
            msg.sender,
            args.account,
            args.data
        );

        Events.logCall(args);
    }

    // ============ Private Functions ============

    /**
     * For the purposes of liquidation or vaporization, get the value-equivalent amount of heldWei
     * given owedWei and the (spread-adjusted) prices of each asset.
     */
    function _owedWeiToHeldWei(
        Types.Wei memory owedWei,
        Monetary.Price memory heldPrice,
        Monetary.Price memory owedPrice
    )
        private
        pure
        returns (Types.Wei memory)
    {
        return Types.Wei({
            sign: false,
            value: Math.getPartial(owedWei.value, owedPrice.value, heldPrice.value)
        });
    }

    /**
     * For the purposes of liquidation or vaporization, get the value-equivalent amount of owedWei
     * given heldWei and the (spread-adjusted) prices of each asset.
     */
    function _heldWeiToOwedWei(
        Types.Wei memory heldWei,
        Monetary.Price memory heldPrice,
        Monetary.Price memory owedPrice
    )
        private
        pure
        returns (Types.Wei memory)
    {
        return Types.Wei({
            sign: true,
            value: Math.getPartialRoundUp(heldWei.value, heldPrice.value, owedPrice.value)
        });
    }

    /**
     * Attempt to vaporize an account's balance using the excess tokens in the protocol. Return a
     * bool and a wei value. The boolean is true if and only if the balance was fully vaporized. The
     * Wei value is how many excess tokens were used to partially or fully vaporize the account's
     * negative balance.
     */
    function _vaporizeUsingExcess(
        Storage.State storage state,
        Actions.VaporizeArgs memory args
    )
        internal
        returns (bool, Types.Wei memory)
    {
        Types.Wei memory excessWei = state.getNumExcessTokens(args.owedMarket);

        // There are no excess funds, return zero
        if (!excessWei.isPositive()) {
            return (false, Types.zeroWei());
        }

        Types.Wei memory maxRefundWei = state.getWei(args.vaporAccount, args.owedMarket);
        maxRefundWei.sign = true;

        // The account is fully vaporizable using excess funds
        if (excessWei.value >= maxRefundWei.value) {
            state.setPar(
                args.vaporAccount,
                args.owedMarket,
                Types.zeroPar()
            );
            return (true, maxRefundWei);
        }

        // The account is only partially vaporizable using excess funds
        else {
            state.setParFromDeltaWei(
                args.vaporAccount,
                args.owedMarket,
                excessWei
            );
            return (false, excessWei);
        }
    }

    /**
     * Return the (spread-adjusted) prices of two assets for the purposes of liquidation or
     * vaporization.
     */
    function _getLiquidationPrices(
        Storage.State storage state,
        Cache.MarketCache memory cache,
        uint256 heldMarketId,
        uint256 owedMarketId
    )
        internal
        view
        returns (
            Monetary.Price memory,
            Monetary.Price memory
        )
    {
        uint256 originalPrice = cache.getPrice(owedMarketId).value;
        Decimal.D256 memory spread = state.getLiquidationSpreadForPair(
            heldMarketId,
            owedMarketId
        );

        Monetary.Price memory owedPrice = Monetary.Price({
            value: originalPrice.add(Decimal.mul(originalPrice, spread))
        });

        return (cache.getPrice(heldMarketId), owedPrice);
    }
}

Contract ABI

[]

615fd962000027600b82828239805160001a60731461001a57fe5b30600052607381538281f3fe7300000000000000000000000000000000000000003014608060405260043610610051577c01000000000000000000000000000000000000000000000000000000006000350463bd76ecfd8114610056575b600080fd5b81801561006257600080fd5b506100766100713660046155ed565b610078565b005b6100806100c2565b61008a82826100fb565b6060610094614f5a565b61009f858585610248565b915091506100af85858584610594565b6100bb85858484610735565b5050505050565b7f91b01baeee3a24b590d112613814d86801005c7ef9353e7fc1eaeaf33ccf83b0336040516100f191906159d0565b60405180910390a1565b61014b8151600014157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f43616e6e6f742068617665207a65726f20616374696f6e7300000000000000006108fc565b61019b8251600014157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f43616e6e6f742068617665207a65726f206163636f756e7473000000000000006108fc565b60005b825181101561024357600181015b835181101561023a576102326101e88584815181106101c757fe5b60200260200101518684815181106101db57fe5b60200260200101516109ad565b157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f43616e6e6f74206475706c6963617465206163636f756e74730000000000000085856109eb565b6001016101ac565b5060010161019e565b505050565b6060610252614f5a565b845484516040805182815260208084028201019091526060918015610281578160200160208202803883390190505b50905061028c614f5a565b61029583610aaf565b905060005b86518110156104fe576102ab614f6d565b8782815181106102b757fe5b6020026020010151905060008160000151905060006102d582610b07565b905060006102e283610b74565b905060008160028111156102f257fe5b146104065761034e8460c00151856020015114157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f4475706c6963617465206163636f756e747320696e20616374696f6e0000000088610be2565b600181600281111561035c57fe5b1415610389576001878560c001518151811061037457fe5b91151560209283029190910190910152610406565b600281600281111561039757fe5b1461039e57fe5b610406878560c00151815181106103b157fe5b6020026020010151157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f5265717569726573206e6f6e2d7072696d617279206163636f756e74000000008760c00151610be2565b60018785602001518151811061041857fe5b91151560209283029190910190910152600182600281111561043657fe5b14156104505761044b8d878660600151610c80565b6104ee565b600282600281111561045e57fe5b14156104d9576104bb8460800151856060015114157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f4475706c6963617465206d61726b65747320696e20616374696f6e000000000088610be2565b6104ca8d878660600151610c80565b61044b8d878660800151610c80565b60008260028111156104e757fe5b146104ee57fe5b50506001909201915061029a9050565b5060005b838110156105865761051a828263ffffffff610cb416565b156105245761057e565b60005b885181101561057c5761056061055b8a838151811061054257fe5b6020026020010151848d610ce29092919063ffffffff16565b610d5e565b6105745761056f8a8484610c80565b61057c565b600101610527565b505b600101610502565b509097909650945050505050565b60005b82518110156100bb576105a8614f6d565b8382815181106105b457fe5b6020908102919091010151805190915060008160088111156105d257fe5b14156105f0576105eb876105e68885610d78565b610df9565b61072b565b60018160088111156105fe57fe5b1415610617576105eb876106128885610f41565b610f50565b600281600881111561062557fe5b141561063e576105eb876106398885610fe9565b611066565b600381600881111561064c57fe5b1415610665576105eb876106608885611116565b6111ab565b600481600881111561067357fe5b141561068c576105eb876106878885611320565b61132f565b600581600881111561069a57fe5b14156106b3576105eb876106ae8885611426565b611486565b60068160088111156106c157fe5b14156106db576105eb876106d5888561170a565b86611792565b60078160088111156106e957fe5b1415610703576105eb876106fd8885611a57565b86611a66565b600881600881111561071157fe5b1461071857fe5b61072b876107268885611d13565b611d89565b5050600101610597565b600061074082611e3b565b905060005b818110156107fc5761075d838263ffffffff611e4016565b156107f4576107f4610775848363ffffffff611e6616565b6fffffffffffffffffffffffffffffffff16610797888463ffffffff611e8c16565b516fffffffffffffffffffffffffffffffff1611157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f4d61726b657420697320636c6f73696e6700000000000000000000000000000084610be2565b600101610745565b5060005b84518110156108f457610811614fcc565b85828151811061081d57fe5b60209081029190910101519050600061083f888387600163ffffffff611eec16565b905085838151811061084d57fe5b60200260200101516108605750506108ec565b6108b5817f4f7065726174696f6e496d706c000000000000000000000000000000000000007f556e646572636f6c6c61746572616c697a6564206163636f756e74000000000085600001518660200151611fd8565b60006108c7898463ffffffff61203a16565b60028111156108d257fe5b146108e9576108e98883600063ffffffff61207c16565b50505b600101610800565b505050505050565b826102435761090a826120f9565b7f3a20000000000000000000000000000000000000000000000000000000000000610934836120f9565b60405160200161094693929190615826565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109a491600401615af7565b60405180910390fd5b8051825160009173ffffffffffffffffffffffffffffffffffffffff91821691161480156109e2575081602001518360200151145b90505b92915050565b846100bb576109f9846120f9565b7f3a20000000000000000000000000000000000000000000000000000000000000610a23856120f9565b7f203c000000000000000000000000000000000000000000000000000000000000610a4d866121f8565b7f2c20000000000000000000000000000000000000000000000000000000000000610a77876121f8565b60405161094697969594939291907f3e00000000000000000000000000000000000000000000000000000000000000906020016158ac565b610ab7614f5a565b604051806020016040528083604051908082528060200260200182016040528015610afc57816020015b610ae9614fe3565b815260200190600190039081610ae15790505b50905290505b919050565b600080826008811115610b1657fe5b1480610b2d57506001826008811115610b2b57fe5b145b80610b4357506002826008811115610b4157fe5b145b15610b5057506001610b02565b6008826008811115610b5e57fe5b1415610b6c57506000610b02565b506002919050565b60006002826008811115610b8457fe5b1480610b9b57506005826008811115610b9957fe5b145b15610ba857506001610b02565b6006826008811115610bb657fe5b1480610bcd57506007826008811115610bcb57fe5b145b15610bda57506002610b02565b506000919050565b83610c7a57610bf0836120f9565b7f3a20000000000000000000000000000000000000000000000000000000000000610c1a846120f9565b7f203c000000000000000000000000000000000000000000000000000000000000610c44856121f8565b6040516109469594939291907f3e000000000000000000000000000000000000000000000000000000000000009060200161584e565b50505050565b6000610c9383858463ffffffff61232616565b90508015610c7a57610c7a82610caf868263ffffffff61240016565b612563565b600082600001518281518110610cc657fe5b6020026020010151604001516000015160001415905092915050565b610cea614fcc565b50815173ffffffffffffffffffffffffffffffffffffffff1660009081526002840160209081526040808320828601518452825280832084845282529182902082518084019093525460ff81161515835261010090046fffffffffffffffffffffffffffffffff16908201525b9392505050565b602001516fffffffffffffffffffffffffffffffff161590565b610d80615007565b60005b82516008811115610d9057fe5b14610d9757fe5b60405180608001604052808360400151815260200184846020015181518110610dbc57fe5b60200260200101518152602001836060015181526020018360a0015173ffffffffffffffffffffffffffffffffffffffff16815250905092915050565b6020810151610e109083903363ffffffff61259f16565b6060810151610ebf9073ffffffffffffffffffffffffffffffffffffffff16331480610e73575081602001516000015173ffffffffffffffffffffffffffffffffffffffff16826060015173ffffffffffffffffffffffffffffffffffffffff16145b7f4f7065726174696f6e496d706c000000000000000000000000000000000000007f496e76616c6964206465706f73697420736f7572636500000000000000000000846060015161264e565b610ec7614fcc565b610ecf614fcc565b602083015160408401518451610eee928792909163ffffffff6126b016565b91509150610f11836020015184604001518487612866909392919063ffffffff16565b610f36610f2b846040015186612b2190919063ffffffff16565b846060015183612b4d565b610c7a848483612bb6565b610f49615007565b6001610d83565b6020810151610f679083903363ffffffff61259f16565b610f6f614fcc565b610f77614fcc565b602083015160408401518451610f96928792909163ffffffff6126b016565b91509150610fb9836020015184604001518487612866909392919063ffffffff16565b610fde610fd3846040015186612b2190919063ffffffff16565b846060015183612c31565b610c7a848483612c99565b610ff161503c565b60028251600881111561100057fe5b1461100757fe5b6040518060800160405280836040015181526020018484602001518151811061102c57fe5b60200260200101518152602001848460c001518151811061104957fe5b602002602001015181526020018360600151815250905092915050565b602081015161107d9083903363ffffffff61259f16565b60408101516110949083903363ffffffff61259f16565b61109c614fcc565b6110a4614fcc565b6020830151606084015184516110c3928792909163ffffffff6126b016565b915091506110e6836020015184606001518487612866909392919063ffffffff16565b61110b836040015184606001516110fc84612cf2565b8792919063ffffffff612d1916565b610c7a848483612da1565b61111e615077565b60035b8251600881111561112e57fe5b1461113557fe5b6040518060c00160405280836040015181526020018484602001518151811061115a57fe5b6020026020010151815260200183606001518152602001836080015181526020018360a0015173ffffffffffffffffffffffffffffffffffffffff1681526020018360e00151815250905092915050565b60208101516111c29083903363ffffffff61259f16565b60006111db826060015184612b2190919063ffffffff16565b905060006111f6836040015185612b2190919063ffffffff16565b9050611200614fcc565b611208614fcc565b602085015160408601518651611227928992909163ffffffff6126b016565b91509150611233614fcc565b61124886608001518587858a60a00151612e45565b9050611252614fcc565b61127087608001518860200151600001518789868c60a00151612f6f565b90506112d28360200151826020015110157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f42757920616d6f756e74206c657373207468616e2070726f6d69736564000000846020015187602001516109eb565b602087015160408801516112ee918a918763ffffffff61286616565b6020870151606088015161130a918a918563ffffffff612d1916565b611316888884866130b6565b5050505050505050565b611328615077565b6004611121565b60208101516113469083903363ffffffff61259f16565b600061135f826040015184612b2190919063ffffffff16565b9050600061137a836060015185612b2190919063ffffffff16565b9050611384614fcc565b61138c614fcc565b6020850151604086015186516113ab928992909163ffffffff6126b016565b915091506113b7614fcc565b6113d586608001518760200151600001518688868b60a00151612f6f565b602087015160408801519192506113f5918991908663ffffffff61286616565b602086015160608701516114119189918463ffffffff612d1916565b61141d8787848461314d565b50505050505050565b61142e6150d0565b60058251600881111561143d57fe5b1461144457fe5b6040518060e00160405280836040015181526020018484602001518151811061146957fe5b60200260200101518152602001848460c001518151811061115a57fe5b602081015161149d9083903363ffffffff61259f16565b604081015160a08201516114b891849163ffffffff61259f16565b6114c0614fcc565b604082015160608301516114db91859163ffffffff610ce216565b90506114e5614fcc565b6114ed614fcc565b60408401516060850151855161150c928892909163ffffffff6126b016565b915091506115186150f1565b8460a0015173ffffffffffffffffffffffffffffffffffffffff1663448f706586606001518760800151886040015189602001518989898d60c001516040518963ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401611593989796959493929190615b66565b608060405180830381600087803b1580156115ad57600080fd5b505af11580156115c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115e591908101906155b1565b90506115ef614fcc565b6115f7614fcc565b60408701516080880151611613918a918663ffffffff6126b016565b9150915061168b611623826131bf565b806116325750611632856131bf565b80611644575084518251151590151514155b7f4f7065726174696f6e496d706c000000000000000000000000000000000000007f5472616465732063616e6e6f74206265206f6e652d73696465640000000000006108fc565b604087015160608801516116a7918a918863ffffffff61286616565b604087015160808801516116c3918a918563ffffffff61286616565b6116e8876020015188606001516116d987612cf2565b8b92919063ffffffff612d1916565b6116fe876020015188608001516116d984612cf2565b611316888886846131c7565b611712615112565b60065b8251600881111561172257fe5b1461172957fe5b6040518060a00160405280836040015181526020018484602001518151811061174e57fe5b60200260200101518152602001848460c001518151811061176b57fe5b60200260200101518152602001836060015181526020018360800151815250905092915050565b60208201516117a99084903363ffffffff61259f16565b60408201516117bf90849063ffffffff61203a16565b60028111156117ca57fe5b600114611860576040820151611848906117ee90859084600063ffffffff611eec16565b157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f556e6c6971756964617461626c65206163636f756e7400000000000000000000856040015160000151866040015160200151611fd8565b6040820151611860908490600163ffffffff61207c16565b611868614fcc565b6040830151608084015161188391869163ffffffff6132ef16565b90506118f061189182613354565b157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f436f6c6c61746572616c2063616e6e6f74206265206e65676174697665000000866040015160000151876040015160200151886080015161336b565b6118f8614fcc565b611900614fcc565b60408501516060860151865161191f928992909163ffffffff61345b16565b9150915061192b615154565b611933615154565b611947888789608001518a60600151613604565b91509150611953614fcc565b61195e848484613693565b90508560200151816020015111156119cd5761197986612cf2565b90506119868184846136d0565b93506119ac8860400151896080015161199d613703565b8c92919063ffffffff61286616565b604088015160608901516119c8918b918763ffffffff612d1916565b611a05565b604088015160608901516119e9918b918863ffffffff61286616565b60408801516080890151611a05918b918463ffffffff612d1916565b611a2a88602001518960600151611a1b87612cf2565b8c92919063ffffffff612d1916565b611a4088602001518960800151611a1b84612cf2565b611a4c89898387613723565b505050505050505050565b611a5f615112565b6007611715565b6020820151611a7d9084903363ffffffff61259f16565b6040820151611a9390849063ffffffff61203a16565b6002811115611a9e57fe5b600214611b2e576040820151611b1690611ac09085908463ffffffff61384616565b604084015180516020909101517f4f7065726174696f6e496d706c00000000000000000000000000000000000000917f556e7661706f72697a61626c65206163636f756e74000000000000000000000091611fd8565b6040820151611b2e908490600263ffffffff61207c16565b6000611b38614fcc565b611b4285856138d5565b915091508115611b6e57611b678585611b59613703565b611b61613703565b856139b5565b5050610243565b611b76614fcc565b6080850151611b8c90879063ffffffff613ab216565b9050611be7611b9a82613354565b157f4f7065726174696f6e496d706c000000000000000000000000000000000000007f4578636573732063616e6e6f74206265206e65676174697665000000000000008860800151610be2565b611bef614fcc565b611bf7614fcc565b604087015160608801518851611c16928b92909163ffffffff61345b16565b91509150611c22615154565b611c2a615154565b611c3e8a898b608001518c60600151613604565b91509150611c4a614fcc565b611c55848484613693565b9050856020015181602001511115611ca257611c7086612cf2565b9050611c7d8184846136d0565b60408b015160608c0151919550611c9d918d91908763ffffffff612d1916565b611cbe565b60408a015160608b0151611cbe918d918863ffffffff61286616565b611ce38a602001518b60600151611cd487612cf2565b8e92919063ffffffff612d1916565b611cf98a602001518b60800151611cd484612cf2565b611d068b8b83878b6139b5565b5050505050505050505050565b611d1b615167565b600882516008811115611d2a57fe5b14611d3157fe5b604051806060016040528084846020015181518110611d4c57fe5b602002602001015181526020018360a0015173ffffffffffffffffffffffffffffffffffffffff1681526020018360e00151815250905092915050565b8051611d9d9083903363ffffffff61259f16565b6020810151815160408084015190517f8b41871300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90931692638b41871392611dfc9233926004016159de565b600060405180830381600087803b158015611e1657600080fd5b505af1158015611e2a573d6000803e3d6000fd5b50505050611e3781613b6c565b5050565b515190565b600082600001518281518110611e5257fe5b602002602001015160000151905092915050565b600082600001518281518110611e7857fe5b602002602001015160200151905092915050565b611e94614fcc565b506000818152600180840160209081526040928390208351808501909452909101546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015292915050565b6000611ef6615154565b611efe615154565b611f11878787600163ffffffff613bcd16565b80519193509150611f2757600192505050611fd0565b8315611f8e576008870154815187516020890151611f8e93831015927f53746f7261676500000000000000000000000000000000000000000000000000927f426f72726f772076616c756520746f6f206c6f7700000000000000000000000092909161336b565b8051604080516020810190915260058901548152600091611fae91613d20565b8251909150611fc3908263ffffffff613d3916565b8360000151101593505050505b949350505050565b846100bb57611fe6846120f9565b7f3a20000000000000000000000000000000000000000000000000000000000000612010856120f9565b7f203c000000000000000000000000000000000000000000000000000000000000610a4d86613d4b565b805173ffffffffffffffffffffffffffffffffffffffff1660009081526002929092016020908152604080842092820151845291905290206001015460ff1690565b815173ffffffffffffffffffffffffffffffffffffffff16600090815260028085016020908152604080842082870151855290915290912060019081018054849391927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091169184908111156120ef57fe5b0217905550505050565b6060808260405160200161210d9190615811565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060205b80156121dd5781517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091019082908290811061217957fe5b6020910101517f010000000000000000000000000000000000000000000000000000000000000090819004027fff0000000000000000000000000000000000000000000000000000000000000016156121d85760010181529050610b02565b612140565b5060408051600080825260208201909252905b509392505050565b606081612239575060408051808201909152600181527f30000000000000000000000000000000000000000000000000000000000000006020820152610b02565b8160005b811561225157600101600a8204915061223d565b6060816040519080825280601f01601f19166020018201604052801561227e576020820181803883390190505b508593509050815b801561231d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600a84066030017f0100000000000000000000000000000000000000000000000000000000000000028282815181106122e357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a84049350612286565b50949350505050565b6000612338848363ffffffff610cb416565b1561234557506000610d57565b612355838363ffffffff613efe16565b845180518490811061236357fe5b602090810291909101810151604090810192909252600084815260018601909152206007015460ff16156123f6576001846000015183815181106123a357fe5b602090810291909101015190151590526123c3838363ffffffff611e8c16565b5184518051849081106123d257fe5b6020908102919091018101516fffffffffffffffffffffffffffffffff9092169101525b5060019392505050565b61240861518e565b61241061518e565b612420848463ffffffff61403f16565b905061242a6140c3565b63ffffffff16816040015163ffffffff1614156124485790506109e5565b61245984848363ffffffff6140d316565b6000938452600194909401602090815260409384902085516002909101805487840151978701517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166bffffffffffffffffffffffff938416177fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000009884168902177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff9283168102919091179283905587516060810189528385168152988304909316938801939093520416928401929092525090919050565b817ff4626fd1187f91e6761ffb8a6ac3e8d9235a4a92da54e43feb0c57c4a4a322ab826040516125939190615b08565b60405180910390a25050565b6000826000015173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614806125ea57506125ea848363ffffffff61412216565b80612604575082516126049085908463ffffffff61415116565b9050610c7a817f53746f72616765000000000000000000000000000000000000000000000000007f556e7065726d697373696f6e6564206f70657261746f72000000000000000000855b83610c7a5761265c836120f9565b7f3a20000000000000000000000000000000000000000000000000000000000000612686846120f9565b7f203c000000000000000000000000000000000000000000000000000000000000610c4485613d4b565b6126b8614fcc565b6126c0614fcc565b6126c8614fcc565b6126d987878763ffffffff610ce216565b9050836060015160001480156126fe57506000846040015160018111156126fc57fe5b145b15612716578061270c613703565b925092505061285d565b61271e61518e565b61272e888763ffffffff61403f16565b9050612738614fcc565b612742838361418e565b905061274c614fcc565b612754614fcc565b60008860200151600181111561276657fe5b14156127d25750604080518082019091528751151581526060880151602082015260018860400151600181111561279957fe5b14156127b2576127af818463ffffffff61423f16565b90505b6127cb6127c5848363ffffffff61425416565b856142e6565b9150612854565b60405180604001604052808960000151151581526020016127f68a606001516143a9565b6fffffffffffffffffffffffffffffffff169052915060008860400151600181111561281e57fe5b141561283757612834858363ffffffff61440b16565b91505b61285183612845848761418e565b9063ffffffff61423f16565b90505b90955093505050505b94509492505050565b61286e614fcc565b61287f85858563ffffffff610ce216565b905061288b8183614530565b156128965750610c7a565b61289e614fcc565b6128ae868563ffffffff611e8c16565b82519091501561291b576128ff6128fa83602001516fffffffffffffffffffffffffffffffff1683602001516fffffffffffffffffffffffffffffffff166145a290919063ffffffff16565b6143a9565b6fffffffffffffffffffffffffffffffff166020820152612960565b6020820151815161294b916128fa916fffffffffffffffffffffffffffffffff908116911663ffffffff6145a216565b6fffffffffffffffffffffffffffffffff1681525b8251156129c5576129a96128fa84602001516fffffffffffffffffffffffffffffffff1683602001516fffffffffffffffffffffffffffffffff16613d3990919063ffffffff16565b6fffffffffffffffffffffffffffffffff166020820152612a0a565b602083015181516129f5916128fa916fffffffffffffffffffffffffffffffff908116911663ffffffff613d3916565b6fffffffffffffffffffffffffffffffff1681525b6000848152600180880160209081526040808420855193018054958301516fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000029481167fffffffffffffffffffffffffffffffff0000000000000000000000000000000090971696909617861693909317909255875173ffffffffffffffffffffffffffffffffffffffff1683526002890181528183208882015184528152818320878452815291208451815492860151909316610100027fffffffffffffffffffffffffffffff00000000000000000000000000000000ff9315157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090931692909217929092161790555050505050565b6000908152600191909101602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b612ba6612b5982613354565b157f45786368616e67650000000000000000000000000000000000000000000000007f43616e6e6f74207472616e73666572496e206e656761746976650000000000008460200151610be2565b61024383833084602001516145b7565b602080830151805191810151604085015173ffffffffffffffffffffffffffffffffffffffff909316927f2bad8bc95088af2c247b30fa2b2e6a0886f88625e0945cd3051008e0e270198f92612c0f90889083886146d3565b8660600151604051612c249493929190615b31565b60405180910390a2505050565b612c8a612c3d82614708565b157f45786368616e67650000000000000000000000000000000000000000000000007f43616e6e6f74207472616e736665724f757420706f73697469766500000000008460200151610be2565b6102438383836020015161471e565b602080830151805191810151604085015173ffffffffffffffffffffffffffffffffffffffff909316927fbc83c08f0b269b1726990c8348ffdf1ae1696244a14868d766e542a2f18cd7d492612c0f90889083886146d3565b612cfa614fcc565b5060408051808201909152815115815260208083015190820152919050565b612d22816131bf565b15612d2c57610c7a565b612d3461518e565b612d44858463ffffffff61403f16565b9050612d4e614fcc565b612d5f86868663ffffffff6132ef16565b9050612d69614fcc565b612d79828563ffffffff61425416565b9050612d83614fcc565b612d8d82856142e6565b90506113168888888463ffffffff61286616565b604082015180516020808501518051818301519290940151606087015173ffffffffffffffffffffffffffffffffffffffff94851695909416937f21281f8d59117d0399dc467dbdd321538ceffe3225e80e2bd4de6f1b3355cbc79392612e0b908a90838a6146d3565b612e278a8a604001518b60600151612e228c612cf2565b6146d3565b604051612e38959493929190615be6565b60405180910390a3505050565b612e4d614fcc565b612ea6612e5984613354565b157f45786368616e67650000000000000000000000000000000000000000000000007f43616e6e6f7420676574436f7374206e656761746976650000000000000000008660200151610be2565b612eae614fcc565b6000815260208401516040517f3a8fdd7d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff891691633a8fdd7d91612f0e918a918a91908990600401615a87565b60206040518083038186803b158015612f2657600080fd5b505afa158015612f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612f5e919081019061566a565b602082015290505b95945050505050565b612f77614fcc565b612fd0612f8384614708565b157f45786368616e67650000000000000000000000000000000000000000000000007f43616e6e6f742065786368616e676520706f73697469766500000000000000008660200151610be2565b612fdb848885612c31565b612fe3614fcc565b6001815260208401516040517f7d98ebac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a1691637d98ebac91613047918b9130918c918c91908b90600401615a0b565b602060405180830381600087803b15801561306157600080fd5b505af1158015613075573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613099919081019061566a565b60208201526130a9868983612b4d565b90505b9695505050505050565b6020808401518051918101516060860151604087015173ffffffffffffffffffffffffffffffffffffffff909416937f2e346762bf4ae4568971c30b51fcebd2138275aafcfe12d872956e9f3e12089393613114908a90848a6146d3565b6131288a8a602001518b604001518a6146d3565b896080015160405161313f96959493929190615c29565b60405180910390a250505050565b6020808401518051918101516040860151606087015173ffffffffffffffffffffffffffffffffffffffff909416937fcc3330184b6d88cad87f9e9543b4d4110a6a3eaf20164ca5252d598d0acba3f1936131ab908a90848a6146d3565b6131288a8a602001518b606001518a6146d3565b602001511590565b6131cf6151ae565b60405180608001604052806131f18787602001518860600151612e2289612cf2565b815260200161320d8787602001518860800151612e2288612cf2565b81526020016132268787604001518860600151886146d3565b815260200161323f8787604001518860800151876146d3565b9052604085015180516020808801518051908201519190930151606089015160808a015195965073ffffffffffffffffffffffffffffffffffffffff9384169593909416937f54d4cc60cf7d570631cc1a58942812cb0fc461713613400f56932040c3497d19938760006020020151886001602002015189600260200201518a600360200201518e60a001516040516132e099989796959493929190615d51565b60405180910390a35050505050565b6132f7614fcc565b6132ff614fcc565b61331085858563ffffffff610ce216565b905061331b81610d5e565b1561333057613328613703565b915050610d57565b61333861518e565b613348868563ffffffff61403f16565b90506130ac828261418e565b80516000901580156109e557505060200151151590565b856108f457613379856120f9565b7f3a200000000000000000000000000000000000000000000000000000000000006133a3866120f9565b7f203c0000000000000000000000000000000000000000000000000000000000006133cd87613d4b565b7f2c200000000000000000000000000000000000000000000000000000000000006133f7886121f8565b7f2c20000000000000000000000000000000000000000000000000000000000000613421896121f8565b604051610946999897969594939291907f3e0000000000000000000000000000000000000000000000000000000000000090602001615928565b613463614fcc565b61346b614fcc565b613473614fcc565b61348487878763ffffffff610ce216565b90506134e561349282614822565b157f53746f72616765000000000000000000000000000000000000000000000000007f4f7765642062616c616e63652063616e6e6f7420626520706f7369746976650089600001518a602001518a61336b565b6134ed614fcc565b6134f5614fcc565b6135078989898963ffffffff6126b016565b9150915061351482614822565b1561353f57613521613703565b915061353c6135378a8a8a63ffffffff6132ef16565b612cf2565b90505b6135d661354b82613354565b158015613584575082602001516fffffffffffffffffffffffffffffffff1684602001516fffffffffffffffffffffffffffffffff1610155b7f53746f72616765000000000000000000000000000000000000000000000000007f4f7765642062616c616e63652063616e6e6f7420696e637265617365000000008b600001518c602001518c61336b565b6135e6838363ffffffff61453016565b156135f6576135f3613703565b90505b909890975095505050505050565b61360c615154565b613614615154565b6000613626868563ffffffff61484a16565b519050613631615154565b61364288878763ffffffff61487416565b905061364c615154565b60405180602001604052806136716136648686613d20565b869063ffffffff613d3916565b90529050613685888863ffffffff61484a16565b999098509650505050505050565b61369b614fcc565b60405180604001604052806000151581526020016136c686602001518560000151876000015161490a565b9052949350505050565b6136d8614fcc565b60405180604001604052806001151581526020016136c686602001518660000151866000015161492c565b61370b614fcc565b50604080518082019091526000808252602082015290565b61372b6151dc565b6137428585602001518660800151612e2287612cf2565b905061374c6151dc565b6137638686602001518760600151612e2287612cf2565b905061376d6151dc565b6137818787604001518860800151886146d3565b905061378b6151dc565b61379f8888604001518960600151886146d3565b905086604001516000015173ffffffffffffffffffffffffffffffffffffffff1687602001516000015173ffffffffffffffffffffffffffffffffffffffff167f1b9e65b359b871d74b1af1fc8b13b11635bfb097c4631b091eb762fda7e67dc78960200151602001518a60400151602001518b608001518c606001518a8a8a8a604051613834989796959493929190615ce4565b60405180910390a35050505050505050565b6000808061385384611e3b565b905060005b818110156138ca57613870858263ffffffff610cb416565b613879576138c2565b613881614fcc565b61389288888463ffffffff610ce216565b905061389d81610d5e565b156138a857506138c2565b8051156138bc576000945050505050610d57565b60019350505b600101613858565b509095945050505050565b60006138df614fcc565b6138e7614fcc565b60608401516138fd90869063ffffffff613ab216565b905061390881614708565b613920576000613916613703565b92509250506139ae565b613928614fcc565b6040850151606086015161394391889163ffffffff6132ef16565b60018152602080820151908401519192501161398a5761397d8560400151866060015161396e613703565b8992919063ffffffff61286616565b6001935091506139ae9050565b604085015160608601516139a69188918563ffffffff612d1916565b506000925090505b9250929050565b6139bd6151dc565b6139d48686602001518760800151612e2288612cf2565b90506139de6151dc565b6139f58787602001518860600151612e2288612cf2565b90506139ff6151dc565b60408701516060880151613a1f918a91612e22898963ffffffff61425416565b905086604001516000015173ffffffffffffffffffffffffffffffffffffffff1687602001516000015173ffffffffffffffffffffffffffffffffffffffff167fefdcfda4e0be180f29bfeebc4bcb6de1e950d70b41e9ee813bff9882ee16ca918960200151602001518a60400151602001518b608001518c606001518989896040516138349796959493929190615c85565b613aba614fcc565b613ac261518e565b613ad2848463ffffffff61403f16565b9050613adc614fcc565b613aec858563ffffffff611e8c16565b90506000613b00868663ffffffff612b2116565b9050613b0a614fcc565b6040518060400160405280600115158152602001613b288430614985565b90529050613b34614fcc565b613b3c614fcc565b613b468587614a2a565b9092509050613b5f82612845858463ffffffff61423f16565b9998505050505050505050565b805180516020918201519183015160405173ffffffffffffffffffffffffffffffffffffffff909216927fab38cdc4a831ebe6542bf277d36b65dbc5c66a4d03ec6cf56ac38de05dc3009892613bc29290615b16565b60405180910390a250565b613bd5615154565b613bdd615154565b613be5615154565b613bed615154565b6000613bf887611e3b565b905060005b81811015613d1157613c15888263ffffffff610cb416565b613c1e57613d09565b613c26614fcc565b613c378b8b8463ffffffff6132ef16565b9050613c42816131bf565b15613c4d5750613d09565b6000613c74613c628b8563ffffffff61484a16565b5160208401519063ffffffff614ad216565b9050613c7e615154565b613c86614af9565b90508915613cbe57600084815260018e01602090815260409182902082519182019092526005909101548152613cbb90614b1b565b90505b825115613ce757613ce0613cd28383614b52565b88519063ffffffff613d3916565b8752613d05565b613d02613cf48383613d20565b87519063ffffffff613d3916565b86525b5050505b600101613bfd565b50919890975095505050505050565b60006109e2838360000151670de0b6b3a764000061490a565b6000828201838110156109e257600080fd5b60408051602a808252606082810190935273ffffffffffffffffffffffffffffffffffffffff841691839160208201818038833901905050905060307f01000000000000000000000000000000000000000000000000000000000000000281600081518110613db657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060787f01000000000000000000000000000000000000000000000000000000000000000281600181518110613e1657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060005b60148110156121f05760028102613e61600f8516614b6b565b838260290381518110613e7057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350601090930492613eb1600f8516614b6b565b838260280381518110613ec057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050601090920491600101613e48565b613f06615154565b600082815260018401602052604090206003015473ffffffffffffffffffffffffffffffffffffffff16613f38615154565b73ffffffffffffffffffffffffffffffffffffffff82166341976e09613f64878763ffffffff612b2116565b6040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401613f9c91906159c2565b60206040518083038186803b158015613fb457600080fd5b505afa158015613fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613fec91908101906155cf565b8051909150611fd09015157f53746f72616765000000000000000000000000000000000000000000000000007f50726963652063616e6e6f74206265207a65726f00000000000000000000000087610be2565b61404761518e565b506000908152600191909101602090815260409182902082516060810184526002909101546bffffffffffffffffffffffff80821683526c0100000000000000000000000082041692820192909252780100000000000000000000000000000000000000000000000090910463ffffffff169181019190915290565b60006140ce42614bcb565b905090565b6140db61518e565b6140e3615154565b6140f485858563ffffffff614c2116565b9050612f66838261410b888863ffffffff611e8c16565b604080516020810190915260078a01548152614d48565b73ffffffffffffffffffffffffffffffffffffffff166000908152600491909101602052604090205460ff1690565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600393909301602090815260408085209290931684525290205460ff1690565b614196614fcc565b602083015183516fffffffffffffffffffffffffffffffff9091169015614202576040805180820190915260018152602084810151908201906141f79084906bffffffffffffffffffffffff16670de0b6b3a764000063ffffffff61490a16565b8152509150506109e5565b6040805180820190915260008152835160208201906141f79084906bffffffffffffffffffffffff16670de0b6b3a764000063ffffffff61492c16565b614247614fcc565b6109e28361425484612cf2565b61425c614fcc565b614264614fcc565b8251845115159015151415614297578351151581526020808501519084015161428d9190613d39565b60208201526109e2565b82602001518460200151106142c0578351151581526020808501519084015161428d91906145a2565b825115158152602080840151908501516142da91906145a2565b60208201529392505050565b6142ee614fcc565b8251156143645760405180604001604052806001151581526020016143496128fa670de0b6b3a764000067ffffffffffffffff1686602001516bffffffffffffffffffffffff16886020015161490a9092919063ffffffff16565b6fffffffffffffffffffffffffffffffff16905290506109e5565b6040805180820190915260008152825160208581015190830191614349916128fa91670de0b6b3a7640000906bffffffffffffffffffffffff1663ffffffff61492c16565b6000816109e56fffffffffffffffffffffffffffffffff821682147f4d617468000000000000000000000000000000000000000000000000000000007f556e73616665206361737420746f2075696e74313238000000000000000000006108fc565b614413614fcc565b61441b614fcc565b8251845115159015151415614479578351151581526020808501519084015161445d916128fa916fffffffffffffffffffffffffffffffff9182169116613d39565b6fffffffffffffffffffffffffffffffff1660208201526109e2565b82602001516fffffffffffffffffffffffffffffffff1684602001516fffffffffffffffffffffffffffffffff16106144df578351151581526020808501519084015161445d916128fa916fffffffffffffffffffffffffffffffff91821691166145a2565b82511515815260208084015190850151614512916128fa916fffffffffffffffffffffffffffffffff91821691166145a2565b6fffffffffffffffffffffffffffffffff1660208201529392505050565b600081602001516fffffffffffffffffffffffffffffffff1683602001516fffffffffffffffffffffffffffffffff1614156145995760208301516fffffffffffffffffffffffffffffffff16614589575060016109e5565b50805182511515901515146109e5565b50600092915050565b6000828211156145b157600080fd5b50900390565b8015806145ef57508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b156145f957610c7a565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516906323b872dd9061464f90869086908690600401615a5f565b600060405180830381600087803b15801561466957600080fd5b505af115801561467d573d6000803e3d6000fd5b50505050610c7a61468c614ea6565b7f546f6b656e0000000000000000000000000000000000000000000000000000007f5472616e7366657246726f6d206661696c6564000000000000000000000000006108fc565b6146db6151dc565b60408051808201909152828152602081016146fd87878763ffffffff610ce216565b905295945050505050565b805160009080156109e557505060200151151590565b801580614740575073ffffffffffffffffffffffffffffffffffffffff821630145b1561474a57610243565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063a9059cbb9061479e9085908590600401615ac1565b600060405180830381600087803b1580156147b857600080fd5b505af11580156147cc573d6000803e3d6000fd5b505050506102436147db614ea6565b7f546f6b656e0000000000000000000000000000000000000000000000000000007f5472616e73666572206661696c656400000000000000000000000000000000006108fc565b805160009080156109e5575050602001516fffffffffffffffffffffffffffffffff16151590565b614852615154565b825180518390811061486057fe5b602002602001015160400151905092915050565b61487c615154565b600680850154600085815260018701602090815260409182902082519182019092529201548252906148b89082906148b390614b1b565b613d20565b90506148f3816148b3876001016000878152602001908152602001600020600601604051806020016040529081600082015481525050614b1b565b604080516020810190915290815295945050505050565b6000611fd082614920868663ffffffff614ad216565b9063ffffffff614eda16565b6000831580614939575082155b1561495057614949600083614eda565b9050610d57565b611fd06001614979846149208361496d8a8a63ffffffff614ad216565b9063ffffffff6145a216565b9063ffffffff613d3916565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8416906370a08231906149da9085906004016159c2565b60206040518083038186803b1580156149f257600080fd5b505afa158015614a06573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506109e2919081019061566a565b614a32614fcc565b614a3a614fcc565b614a42614fcc565b5060408051808201909152600181526020858101516fffffffffffffffffffffffffffffffff1690820152614a75614fcc565b50604080518082019091526000815285516fffffffffffffffffffffffffffffffff166020820152614aa5614fcc565b614aaf838761418e565b9050614ab9614fcc565b614ac3838861418e565b91989197509095505050505050565b600082614ae1575060006109e5565b82820282848281614aee57fe5b04146109e257600080fd5b614b01615154565b506040805160208101909152670de0b6b3a7640000815290565b614b23615154565b604080516020810190915282518190614b4a90670de0b6b3a764000063ffffffff613d3916565b905292915050565b60006109e283670de0b6b3a7640000846000015161490a565b6000600a821015614ba257507f01000000000000000000000000000000000000000000000000000000000000006030820102610b02565b506057017f01000000000000000000000000000000000000000000000000000000000000000290565b6000816109e563ffffffff821682147f4d617468000000000000000000000000000000000000000000000000000000007f556e73616665206361737420746f2075696e74333200000000000000000000006108fc565b614c29615154565b614c31614fcc565b614c41858563ffffffff611e8c16565b9050614c4b614fcc565b614c53614fcc565b614c5d8386614a2a565b91509150614c69615154565b600087815260018901602052604090206004015473ffffffffffffffffffffffffffffffffffffffff1663e8177dcf614ca88a8a63ffffffff612b2116565b846020015186602001516040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401614cec93929190615adc565b60206040518083038186803b158015614d0457600080fd5b505afa158015614d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250614d3c91908101906155cf565b98975050505050505050565b614d5061518e565b614d58614fcc565b614d60614fcc565b614d6a8588614a2a565b915091506000614d786140c3565b90506000614db0614da28a6040015163ffffffff168463ffffffff166145a290919063ffffffff16565b89519063ffffffff614ad216565b90506000614dbd856131bf565b15614dca57506000614dfc565b614dd48288613d20565b9050846020015184602001511015614dfc57614df9818560200151876020015161490a565b90505b81811115614e0657fe5b60408051606081019091528a518190614e4390614e3e906bffffffffffffffffffffffff166149798188670de0b6b3a764000061490a565b614efc565b6bffffffffffffffffffffffff908116825260208d810151920191614e7a91614e3e91166149798187670de0b6b3a764000061490a565b6bffffffffffffffffffffffff1681526020018463ffffffff1681525095505050505050949350505050565b6000803d8015614ebd5760208114614ec657614ed2565b60019150614ed2565b60206000803e60005191505b501515905090565b6000808211614ee857600080fd5b6000828481614ef357fe5b04949350505050565b6000816109e56bffffffffffffffffffffffff821682147f4d617468000000000000000000000000000000000000000000000000000000007f556e73616665206361737420746f2075696e74393600000000000000000000006108fc565b6040518060200160405280606081525090565b604080516101608101825260008082526020820152908101614f8d6150f1565b81526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001606081525090565b604080518082019091526000808252602082015290565b6040805160608101825260008082526020820152908101615002615154565b905290565b60405180610100016040528061501b6150f1565b8152602001615028614fcc565b815260006020820181905260409091015290565b6040518061012001604052806150506150f1565b815260200161505d614fcc565b815260200161506a614fcc565b8152602001600081525090565b60405180610140016040528061508b6150f1565b8152602001615098614fcc565b81526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b6040518061018001604052806150e46150f1565b815260200161508b614fcc565b6040805160808101909152600080825260208201908152602001600061506a565b6040518061014001604052806151266150f1565b8152602001615133614fcc565b8152602001615140614fcc565b815260200160008152602001600081525090565b6040518060200160405280600081525090565b604051806080016040528061517a614fcc565b815260006020820152606060409091015290565b604080516060810182526000808252602082018190529181019190915290565b6040518061020001604052806004905b6151c66151dc565b8152602001906001900390816151be5790505090565b60405180608001604052806151ef614fcc565b8152602001615002614fcc565b60006109e28235615e67565b600082601f83011261521957600080fd5b813561522c61522782615df3565b615dcc565b81815260209384019390925082018360005b8381101561526a57813586016152548882615371565b845250602092830192919091019060010161523e565b5050505092915050565b600082601f83011261528557600080fd5b813561529361522782615df3565b915081818352602084019350602081019050838560408402820111156152b857600080fd5b60005b8381101561526a57816152ce888261551f565b845250602090920191604091909101906001016152bb565b60006109e28235615e72565b60006109e28251615e72565b600082601f83011261530f57600080fd5b813561531d61522782615e14565b9150808252602083016020830185838301111561533957600080fd5b615344838284615f3f565b50505092915050565b60006109e28235615f0c565b60006109e28235615f1f565b60006109e28251615f1f565b6000610160828403121561538457600080fd5b61538f610100615dcc565b9050600061539d848461534d565b82525060206153ae84848301615599565b60208301525060406153c28482850161544d565b60408301525060c06153d684828501615599565b60608301525060e06153ea84828501615599565b6080830152506101006153ff848285016151fc565b60a08301525061012061541484828501615599565b60c08301525061014082013567ffffffffffffffff81111561543557600080fd5b615441848285016152fe565b60e08301525092915050565b60006080828403121561545f57600080fd5b6154696080615dcc565b9050600061547784846152e6565b825250602061548884848301615359565b602083015250604061549c84828501615359565b60408301525060606154b084828501615599565b60608301525092915050565b6000608082840312156154ce57600080fd5b6154d86080615dcc565b905060006154e684846152f2565b82525060206154f784848301615365565b602083015250604061550b84828501615365565b60408301525060606154b0848285016155a5565b60006040828403121561553157600080fd5b61553b6040615dcc565b9050600061554984846151fc565b825250602061555a84848301615599565b60208301525092915050565b60006020828403121561557857600080fd5b6155826020615dcc565b9050600061559084846155a5565b82525092915050565b60006109e28235615ec1565b60006109e28251615ec1565b6000608082840312156155c357600080fd5b6000611fd084846154bc565b6000602082840312156155e157600080fd5b6000611fd08484615566565b60008060006060848603121561560257600080fd5b600061560e8686615599565b935050602084013567ffffffffffffffff81111561562b57600080fd5b61563786828701615274565b925050604084013567ffffffffffffffff81111561565457600080fd5b61566086828701615208565b9150509250925092565b60006020828403121561567c57600080fd5b6000611fd084846155a5565b61569181615f2e565b82525050565b61569181615e67565b61569181615e72565b6156916156b582615e77565b615ec1565b6156916156b582615e9c565b6156916156b582615ec1565b60006156dd82615e5a565b6156e78185615e5e565b93506156f7818560208601615f4b565b61570081615f77565b9093019392505050565b600061571582615e5a565b61571f8185610b02565b935061572f818560208601615f4b565b9290920192915050565b8051608083019061574a84826157dc565b506020820151610c7a60408501826157b8565b8051606083019061576e8482615808565b5060208201516157816020850182615808565b506040820151610c7a60408501826157ff565b805160408301906157a58482615697565b506020820151610c7a60208501826157f6565b805160408301906157c984826156a0565b506020820151610c7a60208501826157ed565b805160408301906157a584826156a0565b61569181615ec4565b61569181615ec1565b61569181615ef2565b61569181615efb565b600061581d82846156c6565b50602001919050565b6000615832828661570a565b915061583e82856156ba565b600282019150612f66828461570a565b600061585a828961570a565b915061586682886156ba565b600282019150615876828761570a565b915061588282866156ba565b600282019150615892828561570a565b915061589e82846156a9565b506001019695505050505050565b60006158b8828b61570a565b91506158c4828a6156ba565b6002820191506158d4828961570a565b91506158e082886156ba565b6002820191506158f0828761570a565b91506158fc82866156ba565b60028201915061590c828561570a565b915061591882846156a9565b5060010198975050505050505050565b6000615934828d61570a565b9150615940828c6156ba565b600282019150615950828b61570a565b915061595c828a6156ba565b60028201915061596c828961570a565b915061597882886156ba565b600282019150615988828761570a565b915061599482866156ba565b6002820191506159a4828561570a565b91506159b082846156a9565b506001019a9950505050505050505050565b602081016109e58284615697565b602081016109e58284615688565b608081016159ec8286615688565b6159f96020830185615794565b8181036060830152612f6681846156d2565b60c08101615a198289615697565b615a266020830188615697565b615a336040830187615697565b615a406060830186615697565b615a4d60808301856157f6565b81810360a0830152614d3c81846156d2565b60608101615a6d8286615697565b615a7a6020830185615697565b611fd060408301846157f6565b60808101615a958287615697565b615aa26020830186615697565b615aaf60408301856157f6565b81810360608301526130ac81846156d2565b60408101615acf8285615697565b610d5760208301846157f6565b60608101615aea8286615697565b615a7a60208301856157f6565b602080825281016109e281846156d2565b606081016109e5828461575d565b60408101615b2482856157f6565b610d576020830184615697565b60e08101615b3f82876157f6565b615b4c60208301866157f6565b615b596040830185615739565b612f6660c0830184615697565b6101a08101615b75828b6157f6565b615b82602083018a6157f6565b615b8f6040830189615794565b615b9c6080830188615794565b615ba960c08301876157b8565b615bb76101008301866157b8565b615bc56101408301856157dc565b818103610180830152615bd881846156d2565b9a9950505050505050505050565b6101608101615bf582886157f6565b615c0260208301876157f6565b615c0f60408301866157f6565b615c1c6060830185615739565b6130ac60e0830184615739565b6101808101615c3882896157f6565b615c4560208301886157f6565b615c5260408301876157f6565b615c5f6060830186615739565b615c6c60e0830185615739565b615c7a610160830184615697565b979650505050505050565b6102008101615c94828a6157f6565b615ca160208301896157f6565b615cae60408301886157f6565b615cbb60608301876157f6565b615cc86080830186615739565b615cd6610100830185615739565b614d3c610180830184615739565b6102808101615cf3828b6157f6565b615d00602083018a6157f6565b615d0d60408301896157f6565b615d1a60608301886157f6565b615d276080830187615739565b615d35610100830186615739565b615d43610180830185615739565b613b5f610200830184615739565b6102a08101615d60828c6157f6565b615d6d602083018b6157f6565b615d7a604083018a6157f6565b615d8760608301896157f6565b615d946080830188615739565b615da2610100830187615739565b615db0610180830186615739565b615dbe610200830185615739565b615bd8610280830184615697565b60405181810167ffffffffffffffff81118282101715615deb57600080fd5b604052919050565b600067ffffffffffffffff821115615e0a57600080fd5b5060209081020190565b600067ffffffffffffffff821115615e2b57600080fd5b506020601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b5190565b90815260200190565b60006109e582615ed9565b151590565b7fff000000000000000000000000000000000000000000000000000000000000001690565b7fffff0000000000000000000000000000000000000000000000000000000000001690565b90565b6fffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b63ffffffff1690565b6bffffffffffffffffffffffff1690565b600060098210615f1b57600080fd5b5090565b600060028210615f1b57600080fd5b60006109e58260006109e582615e67565b82818337506000910152565b60005b83811015615f66578181015183820152602001615f4e565b83811115610c7a5750506000910152565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169056fea265627a7a72305820a49126c145898ce1917c321b14ce2c1922b5f712fcd6e4a142e608deff2da2f96c6578706572696d656e74616cf50037

Deployed ByteCode Sourcemap

86092:26503:0:-;;;;;;;;;;;;;;;;;;;;;;;;86445:718;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;86445:718:0;;;;;;;;:::i;:::-;;;86626:21;:19;:21::i;:::-;86660:32;86674:8;86684:7;86660:13;:32::i;:::-;86720:29;86764:30;;:::i;:::-;86808:93;86840:5;86860:8;86883:7;86808:17;:93::i;:::-;86705:196;;;;86914:107;86940:5;86960:8;86983:7;87005:5;86914:11;:107::i;:::-;87034:121;87066:5;87086:8;87109:15;87139:5;87034:17;:121::i;:::-;86445:718;;;;;:::o;72754:95::-;72817:24;72830:10;72817:24;;;;;;;;;;;;;;;72754:95::o;87224:810::-;87388:117;87415:7;:14;87433:1;87415:19;;87449:4;87388:117;:12;:117::i;:::-;87518:119;87545:8;:15;87564:1;87545:20;;87580:4;87518:119;:12;:119::i;:::-;87655:9;87650:377;87674:8;:15;87670:1;:19;87650:377;;;87732:1;87728:5;;87711:305;87739:8;:15;87735:1;:19;87711:305;;;87780:220;87816:40;87831:8;87840:1;87831:11;;;;;;;;;;;;;;87844:8;87853:1;87844:11;;;;;;;;;;;;;;87816:14;:40::i;:::-;87815:41;87879:4;87780:220;87956:1;87980;87780:12;:220::i;:::-;87756:3;;87711:305;;;-1:-1:-1;87691:3:0;;87650:377;;;;87224:810;;:::o;88042:3053::-;88250:13;88278:24;;:::i;:::-;88351:16;;88421:15;;88410:27;;;;;;;;;;;;;;;;88378:29;;88410:27;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;88410:27:0;;88378:59;;88448:30;;:::i;:::-;88481:24;88494:10;88481:12;:24::i;:::-;88448:57;-1:-1:-1;88597:9:0;88592:1998;88616:7;:14;88612:1;:18;88592:1998;;;88652:29;;:::i;:::-;88684:7;88692:1;88684:10;;;;;;;;;;;;;;88652:42;;88709:29;88741:3;:14;;;88709:46;;88770:33;88806:35;88830:10;88806:23;:35::i;:::-;88770:71;;88856:35;88894:36;88919:10;88894:24;:36::i;:::-;88856:74;-1:-1:-1;89011:32:0;88994:13;:49;;;;;;;;;88990:810;;89064:193;89116:3;:18;;;89099:3;:13;;;:35;;89157:4;89064:193;89237:1;89064:12;:193::i;:::-;89297:32;89280:13;:49;;;;;;;;;89276:509;;;89392:4;89354:15;89370:3;:18;;;89354:35;;;;;;;;:42;;;:35;;;;;;;;;;;:42;89276:509;;;89469:41;89452:13;:58;;;;;;;;;89445:66;;;;89534:231;89574:15;89590:3;:18;;;89574:35;;;;;;;;;;;;;;89573:36;89636:4;89534:231;89724:3;:18;;;89534:12;:231::i;:::-;89847:4;89814:15;89830:3;:13;;;89814:30;;;;;;;;:37;;;:30;;;;;;;;;;;:37;89936:30;89920:12;:46;;;;;;;;;89916:663;;;89987:48;90001:5;90008;90015:3;:19;;;89987:13;:48::i;:::-;89916:663;;;90077:31;90061:12;:47;;;;;;;;;90057:522;;;90129:201;90187:3;:21;;;90164:3;:19;;;:44;;90231:4;90129:201;90310:1;90129:12;:201::i;:::-;90349:48;90363:5;90370;90377:3;:19;;;90349:13;:48::i;:::-;90416:50;90430:5;90437;90444:3;:21;;;90416:13;:50::i;90057:522::-;90530:32;90514:12;:48;;;;;;;;;90507:56;;;;-1:-1:-1;;88632:3:0;;;;;-1:-1:-1;88592:1998:0;;-1:-1:-1;88592:1998:0;;-1:-1:-1;90676:9:0;90671:373;90695:10;90691:1;:14;90671:373;;;90731:18;:5;90747:1;90731:18;:15;:18;:::i;:::-;90727:67;;;90770:8;;90727:67;90813:9;90808:225;90832:8;:15;90828:1;:19;90808:225;;;90878:37;:28;90891:8;90900:1;90891:11;;;;;;;;;;;;;;90904:1;90878:5;:12;;:28;;;;;:::i;:::-;:35;:37::i;:::-;90873:145;;90940:30;90954:5;90961;90968:1;90940:13;:30::i;:::-;90993:5;;90873:145;90849:3;;90808:225;;;;90671:373;90707:3;;90671:373;;;-1:-1:-1;91064:15:0;;;;-1:-1:-1;88042:3053:0;-1:-1:-1;;;;;88042:3053:0:o;91445:1858::-;91677:9;91672:1624;91696:7;:14;91692:1;:18;91672:1624;;;91732:32;;:::i;:::-;91767:7;91775:1;91767:10;;;;;;;;;;;;;;;;;;91824:17;;91767:10;;-1:-1:-1;91792:29:0;91862:10;:40;;;;;;;;;91858:1427;;;91923:59;91932:5;91939:42;91964:8;91974:6;91939:24;:42::i;:::-;91923:8;:59::i;:::-;91858:1427;;;92035:27;92021:10;:41;;;;;;;;;92017:1268;;;92083:61;92093:5;92100:43;92126:8;92136:6;92100:25;:43::i;:::-;92083:9;:61::i;92017:1268::-;92197:27;92183:10;:41;;;;;;;;;92179:1106;;;92245:61;92255:5;92262:43;92288:8;92298:6;92262:25;:43::i;:::-;92245:9;:61::i;92179:1106::-;92359:22;92345:10;:36;;;;;;;;;92341:944;;;92402:51;92407:5;92414:38;92435:8;92445:6;92414:20;:38::i;:::-;92402:4;:51::i;92341:944::-;92506:23;92492:10;:37;;;;;;;;;92488:797;;;92550:53;92556:5;92563:39;92585:8;92595:6;92563:21;:39::i;:::-;92550:5;:53::i;92488:797::-;92656:24;92642:10;:38;;;;;;;;;92638:647;;;92701:55;92708:5;92715:40;92738:8;92748:6;92715:22;:40::i;:::-;92701:6;:55::i;92638:647::-;92809:28;92795:10;:42;;;;;;;;;92791:494;;;92858:70;92869:5;92876:44;92903:8;92913:6;92876:26;:44::i;:::-;92922:5;92858:10;:70::i;92791:494::-;92981:27;92967:10;:41;;;;;;;;;92963:322;;;93029:68;93039:5;93046:43;93072:8;93082:6;93046:25;:43::i;:::-;93091:5;93029:9;:68::i;92963:322::-;93173:23;93159:10;:37;;;;;;;;;93152:45;;;;93216:53;93222:5;93229:39;93251:8;93261:6;93229:21;:39::i;:::-;93216:5;:53::i;:::-;-1:-1:-1;;91712:3:0;;91672:1624;;93311:1618;93602:18;93623:21;:5;:19;:21::i;:::-;93602:42;-1:-1:-1;93660:9:0;93655:328;93679:10;93675:1;:14;93655:328;;;93715:21;:5;93734:1;93715:21;:18;:21;:::i;:::-;93711:261;;;93757:199;93823:21;:5;93842:1;93823:21;:18;:21;:::i;:::-;93792:52;;:20;:5;93810:1;93792:20;:17;:20;:::i;:::-;:27;:52;;;;93867:4;93757:199;93936:1;93757:12;:199::i;:::-;93691:3;;93655:328;;;-1:-1:-1;94045:9:0;94040:882;94064:8;:15;94060:1;:19;94040:882;;;94101:27;;:::i;:::-;94131:8;94140:1;94131:11;;;;;;;;;;;;;;;;;;;-1:-1:-1;94201:19:0;94223:44;:5;94131:11;94255:5;94262:4;94223:44;:22;:44;:::i;:::-;94201:66;;94360:15;94376:1;94360:18;;;;;;;;;;;;;;94355:68;;94399:8;;;;94355:68;94500:196;94531:14;94564:4;94500:196;94635:7;:13;;;94667:7;:14;;;94500:12;:196::i;:::-;94806:21;94778:24;:5;94794:7;94778:24;:15;:24;:::i;:::-;:49;;;;;;;;;94774:137;;94848:47;:5;94864:7;94873:21;94848:47;:15;:47;:::i;:::-;94040:882;;;94081:3;;94040:882;;;;93311:1618;;;;;:::o;3406:427::-;3548:4;3543:283;;3666:15;3676:4;3666:9;:15::i;:::-;3708:5;3740:17;3750:6;3740:9;:17::i;:::-;3623:157;;;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;3623:157:0;;;;3569:245;;;;;;;;;;;;;;;;;19550:200;19711:7;;19700;;19671:4;;19700:18;;;;;;;:42;;;;;19734:1;:8;;;19722:1;:8;;;:20;19700:42;19693:49;;19550:200;;;;;:::o;4415:671::-;4611:4;4606:473;;4729:15;4739:4;4729:9;:15::i;:::-;4771:5;4803:17;4813:6;4803:9;:17::i;:::-;4847:6;4880:19;4890:8;4880:9;:19::i;:::-;4926:5;4958:19;4968:8;4958:9;:19::i;:::-;4686:347;;;;;;;;;;;5004:6;;4686:347;;;;35973:229;36075:18;;:::i;:::-;36118:76;;;;;;;;36171:10;36154:28;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;36118:76:0;;36111:83;-1:-1:-1;35973:229:0;;;;:::o;29139:550::-;29253:12;;29301:10;:40;;;;;;;;;:98;;;-1:-1:-1;29372:27:0;29358:10;:41;;;;;;;;;29301:98;:156;;;-1:-1:-1;29430:27:0;29416:10;:41;;;;;;;;;29301:156;29283:358;;;-1:-1:-1;29491:22:0;29484:29;;29283:358;29558:23;29544:10;:37;;;;;;;;;29540:101;;;-1:-1:-1;29605:24:0;29598:31;;29540:101;-1:-1:-1;29658:23:0;29139:550;;;:::o;29697:582::-;29812:13;29875:27;29861:10;:41;;;;;;;;;:96;;;-1:-1:-1;29933:24:0;29919:10;:38;;;;;;;;;29861:96;29843:387;;;-1:-1:-1;29991:24:0;29984:31;;29843:387;30065:28;30051:10;:42;;;;;;;;;:100;;;-1:-1:-1;30124:27:0;30110:10;:41;;;;;;;;;30051:100;30033:197;;;-1:-1:-1;30185:33:0;30178:40;;30033:197;-1:-1:-1;30247:24:0;29697:582;;;:::o;3841:566::-;4010:4;4005:395;;4128:15;4138:4;4128:9;:15::i;:::-;4170:5;4202:17;4212:6;4202:9;:17::i;:::-;4246:6;4279:19;4289:8;4279:9;:19::i;:::-;4085:269;;;;;;;;;4325:6;;4085:269;;;;4005:395;3841:566;;;;:::o;91103:334::-;91272:12;91287:32;:5;91303;91310:8;91287:32;:15;:32;:::i;:::-;91272:47;;91334:7;91330:100;;;91358:60;91380:8;91390:27;:5;91380:8;91390:27;:17;:27;:::i;:::-;91358:21;:60::i;37225:215::-;37363:4;37392:5;:13;;;37406:8;37392:23;;;;;;;;;;;;;;:29;;;:35;;;37431:1;37392:40;;37385:47;;37225:215;;;;:::o;56450:289::-;56626:16;;:::i;:::-;-1:-1:-1;56682:13:0;;56667:29;;;;;;:14;;;:29;;;;;;;;56697:14;;;;56667:45;;;;;;;:64;;;;;;;;;56660:71;;;;;;;;;;;;;;;;;;;;;;;;;56450:289;;;;;;:::o;15926:145::-;16051:7;;;:12;;;;15926:145::o;30341:451::-;30498:18;;:::i;:::-;30560;30541:37;:15;;:37;;;;;;;;;30534:45;;;;30597:187;;;;;;;;30632:4;:11;;;30597:187;;;;30667:8;30676:4;:14;;;30667:24;;;;;;;;;;;;;;30597:187;;;;30714:4;:20;;;30597:187;;;;30755:4;:17;;;30597:187;;;;;30590:194;;30341:451;;;;:::o;94990:993::-;95152:12;;;;95128:49;;:5;;95166:10;95128:49;:23;:49;:::i;:::-;95217:9;;;;95190:178;;95217:23;;95230:10;95217:23;;:58;;;95257:4;:12;;;:18;;;95244:31;;:4;:9;;;:31;;;95217:58;95290:4;95190:178;95348:4;:9;;;95190:12;:178::i;:::-;95396:23;;:::i;:::-;95434:25;;:::i;:::-;95514:12;;;;95541:11;;;;95567;;95473:116;;:5;;95514:12;;95473:116;:26;:116;:::i;:::-;95381:208;;;;95602:97;95629:4;:12;;;95656:4;:11;;;95682:6;95602:5;:12;;:97;;;;;;:::i;:::-;95753:119;95787:27;95802:4;:11;;;95787:5;:14;;:27;;;;:::i;:::-;95829:4;:9;;;95853:8;95753:19;:119::i;:::-;95885:90;95917:5;95937:4;95956:8;95885:17;:90::i;30800:453::-;30958:19;;:::i;:::-;31021;31002:38;;95991:804;96155:12;;;;96131:49;;:5;;96169:10;96131:49;:23;:49;:::i;:::-;96208:23;;:::i;:::-;96246:25;;:::i;:::-;96326:12;;;;96353:11;;;;96379;;96285:116;;:5;;96326:12;;96285:116;:26;:116;:::i;:::-;96193:208;;;;96414:97;96441:4;:12;;;96468:4;:11;;;96494:6;96414:5;:12;;:97;;;;;;:::i;:::-;96565:118;96600:27;96615:4;:11;;;96600:5;:14;;:27;;;;:::i;:::-;96642:4;:7;;;96664:8;96565:20;:118::i;:::-;96696:91;96729:5;96749:4;96768:8;96696:18;:91::i;31261:476::-;31419:19;;:::i;:::-;31482;31463:15;;:38;;;;;;;;;31456:46;;;;31520:209;;;;;;;;31556:4;:11;;;31520:209;;;;31594:8;31603:4;:14;;;31594:24;;;;;;;;;;;;;;31520:209;;;;31645:8;31654:4;:19;;;31645:29;;;;;;;;;;;;;;31520:209;;;;31697:4;:20;;;31520:209;;;31513:216;;31261:476;;;;:::o;96803:842::-;96967:15;;;;96943:52;;:5;;96984:10;96943:52;:23;:52;:::i;:::-;97030:15;;;;97006:52;;:5;;97047:10;97006:52;:23;:52;:::i;:::-;97086:23;;:::i;:::-;97124:25;;:::i;:::-;97204:15;;;;97234:11;;;;97260;;97163:119;;:5;;97204:15;;97163:119;:26;:119;:::i;:::-;97071:211;;;;97295:100;97322:4;:15;;;97352:4;:11;;;97378:6;97295:5;:12;;:100;;;;;;:::i;:::-;97408:125;97447:4;:15;;;97477:4;:11;;;97503:19;:8;:17;:19::i;:::-;97408:5;;:125;;;:24;:125;:::i;:::-;97546:91;97579:5;97599:4;97618:8;97546:18;:91::i;31745:536::-;31898:14;;:::i;:::-;31956;31937:33;:15;;:33;;;;;;;;;31930:41;;;;31989:284;;;;;;;;32020:4;:11;;;31989:284;;;;32055:8;32064:4;:14;;;32055:24;;;;;;;;;;;;;;31989:284;;;;32107:4;:20;;;31989:284;;;;32155:4;:22;;;31989:284;;;;32209:4;:17;;;31989:284;;;;;;32252:4;:9;;;31989:284;;;31982:291;;31745:536;;;;:::o;97653:1581::-;97807:12;;;;97783:49;;:5;;97821:10;97783:49;:23;:49;:::i;:::-;97845:18;97866:32;97881:4;:16;;;97866:5;:14;;:32;;;;:::i;:::-;97845:53;;97909:18;97930:32;97945:4;:16;;;97930:5;:14;;:32;;;;:::i;:::-;97909:53;;97990:25;;:::i;:::-;98030;;:::i;:::-;98110:12;;;;98137:16;;;;98168:11;;98069:121;;:5;;98110:12;;98069:121;:26;:121;:::i;:::-;97975:215;;;;98203:25;;:::i;:::-;98231:164;98262:4;:20;;;98297:10;98322;98347:8;98370:4;:14;;;98231:16;:164::i;:::-;98203:192;;98408:31;;:::i;:::-;98442:198;98474:4;:20;;;98509:4;:12;;;:18;;;98542:10;98567;98592:8;98615:4;:14;;;98442:17;:198::i;:::-;98408:232;;98653:205;98704:8;:14;;;98680;:20;;;:38;;98733:4;98653:205;98798:14;:20;;;98833:8;:14;;;98653:12;:205::i;:::-;98898:12;;;;98925:16;;;;98871:104;;:5;;98956:8;98871:104;:12;:104;:::i;:::-;99027:12;;;;99054:16;;;;98988:116;;:5;;99085:8;98988:116;:24;:116;:::i;:::-;99117:109;99145:5;99165:4;99184:8;99207;99117:13;:109::i;:::-;97653:1581;;;;;;;;:::o;32289:540::-;32443:15;;:::i;:::-;32502;32483:34;;99242:1155;99398:12;;;;99374:49;;:5;;99412:10;99374:49;:23;:49;:::i;:::-;99436:18;99457:32;99472:4;:16;;;99457:5;:14;;:32;;;;:::i;:::-;99436:53;;99500:18;99521:32;99536:4;:16;;;99521:5;:14;;:32;;;;:::i;:::-;99500:53;;99581:25;;:::i;:::-;99621;;:::i;:::-;99701:12;;;;99728:16;;;;99759:11;;99660:121;;:5;;99701:12;;99660:121;:26;:121;:::i;:::-;99566:215;;;;99794:25;;:::i;:::-;99822:198;99854:4;:20;;;99889:4;:12;;;:18;;;99922:10;99947;99972:8;99995:4;:14;;;99822:17;:198::i;:::-;100060:12;;;;100087:16;;;;99794:226;;-1:-1:-1;100033:104:0;;:5;;100060:12;100118:8;100033:104;:12;:104;:::i;:::-;100189:12;;;;100216:16;;;;100150:116;;:5;;100247:8;100150:116;:24;:116;:::i;:::-;100279:110;100308:5;100328:4;100347:8;100370;100279:14;:110::i;:::-;99242:1155;;;;;;;:::o;32837:603::-;32992:16;;:::i;:::-;33052;33033:15;;:35;;;;;;;;;33026:43;;;;33087:345;;;;;;;;33120:4;:11;;;33087:345;;;;33160:8;33169:4;:14;;;33160:24;;;;;;;;;;;;;;33087:345;;;;33213:8;33222:4;:19;;;33213:29;;;;;;;100405:2142;100563:17;;;;100539:54;;:5;;100582:10;100539:54;:23;:54;:::i;:::-;100628:17;;;;100647:15;;;;100604:59;;:5;;:59;:23;:59;:::i;:::-;100676:28;;:::i;:::-;100734:17;;;;100766:16;;;;100707:86;;:5;;:86;:12;:86;:::i;:::-;100676:117;;100819:28;;:::i;:::-;100862:25;;:::i;:::-;100942:17;;;;100974:16;;;;101005:11;;100901:126;;:5;;100942:17;;100901:126;:26;:126;:::i;:::-;100804:223;;;;101040:37;;:::i;:::-;101092:4;:15;;;101080:41;;;101136:4;:16;;;101167:4;:17;;;101199:4;:17;;;101231:4;:17;;;101263:11;101289;101315:8;101338:4;:14;;;101080:283;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;101080:283:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;101080:283:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;101080:283:0;;;;;;;;;101040:323;;101391:29;;:::i;:::-;101435:26;;:::i;:::-;101516:17;;;;101548;;;;101475:128;;:5;;101580:12;101475:128;:26;:128;:::i;:::-;101376:227;;;;101616:174;101643:18;:9;:16;:18::i;:::-;:39;;;;101665:17;:8;:15;:17::i;:::-;101643:74;;;-1:-1:-1;101704:13:0;;101686:14;;:31;;;;;;;101643:74;101732:4;101616:174;:12;:174::i;:::-;101872:17;;;;101904:16;;;;101845:112;;:5;;101935:11;101845:112;:12;:112;:::i;:::-;101995:17;;;;102027;;;;101968:114;;:5;;102059:12;101968:114;:12;:114;:::i;:::-;102137:132;102176:4;:17;;;102208:4;:16;;;102239:19;:8;:17;:19::i;:::-;102137:5;;:132;;;:24;:132;:::i;:::-;102280:134;102319:4;:17;;;102351:4;:17;;;102383:20;:9;:18;:20::i;102280:134::-;102427:112;102457:5;102477:4;102496:8;102519:9;102427:15;:112::i;33448:538::-;33607:20;;:::i;:::-;33671;33652:39;:15;;:39;;;;;;;;;33645:47;;;;33710:268;;;;;;;;33747:4;:11;;;33710:268;;;;33787:8;33796:4;:14;;;33787:24;;;;;;;;;;;;;;33710:268;;;;33841:8;33850:4;:19;;;33841:29;;;;;;;;;;;;;;33710:268;;;;33897:4;:20;;;33710:268;;;;33944:4;:22;;;33710:268;;;33703:275;;33448:538;;;;:::o;102555:3029::-;102762:17;;;;102738:54;;:5;;102781:10;102738:54;:23;:54;:::i;:::-;102882:18;;;;102866:35;;:5;;:35;:15;:35;:::i;:::-;102841:60;;;;;;;;:21;:60;102837:447;;102973:18;;;;102918:281;;102950:81;;:5;;102993;103025;102950:81;:22;:81;:::i;:::-;102949:82;103050:4;102918:281;103116:4;:18;;;:24;;;103159:4;:18;;;:25;;;102918:12;:281::i;:::-;103230:18;;;;103214:58;;:5;;103250:21;103214:58;:15;:58;:::i;:::-;103296:27;;:::i;:::-;103353:18;;;;103386:15;;;;103326:86;;:5;;:86;:12;:86;:::i;:::-;103296:116;;103425:236;103453:23;:10;:21;:23::i;:::-;103452:24;103491:4;103425:236;103556:4;:18;;;:24;;;103595:4;:18;;;:25;;;103635:4;:15;;;103425:12;:236::i;:::-;103689:24;;:::i;:::-;103728;;:::i;:::-;103821:18;;;;103854:15;;;;103884:11;;103766:140;;:5;;103821:18;;103766:140;:40;:140;:::i;:::-;103674:232;;;;103934:31;;:::i;:::-;103980;;:::i;:::-;104025:132;104061:5;104081;104101:4;:15;;;104131:4;:15;;;104025:21;:132::i;:::-;103919:238;;;;104170:24;;:::i;:::-;104197:48;104215:7;104224:9;104235;104197:17;:48::i;:::-;104170:75;;104359:10;:16;;;104343:7;:13;;;:32;104339:777;;;104402:21;:10;:19;:21::i;:::-;104392:31;;104448:48;104466:7;104475:9;104486;104448:17;:48::i;:::-;104438:58;;104513:132;104544:4;:18;;;104581:4;:15;;;104615;:13;:15::i;:::-;104513:5;;:132;;;:12;:132;:::i;:::-;104703:18;;;;104740:15;;;;104660:136;;:5;;104774:7;104660:136;:24;:136;:::i;:::-;104339:777;;;104860:18;;;;104897:15;;;;104829:124;;:5;;104931:7;104829:124;:12;:124;:::i;:::-;105011:18;;;;105048:15;;;;104968:136;;:5;;105082:7;104968:136;:24;:136;:::i;:::-;105179:130;105218:4;:17;;;105250:4;:15;;;105280:18;:7;:16;:18::i;:::-;105179:5;;:130;;;:24;:130;:::i;:::-;105320;105359:4;:17;;;105391:4;:15;;;105421:18;:7;:16;:18::i;105320:130::-;105463:113;105497:5;105517:4;105536:7;105558;105463:19;:113::i;:::-;102555:3029;;;;;;;;;:::o;33994:533::-;34152:19;;:::i;:::-;34215;34196:38;;105592:3017;105797:17;;;;105773:54;;:5;;105816:10;105773:54;:23;:54;:::i;:::-;105915:17;;;;105899:34;;:5;;:34;:15;:34;:::i;:::-;105875:58;;;;;;;;:20;:58;105871:403;;106001:17;;;;105950:241;;105981:45;;:5;;106020;105981:45;:19;:45;:::i;:::-;106110:17;;;;:23;;106152:24;;;;;106045:4;;105950:241;;:12;:241::i;:::-;106222:17;;;;106206:56;;:5;;106241:20;106206:56;:15;:56;:::i;:::-;106359:16;106390:26;;:::i;:::-;106430:33;106451:5;106458:4;106430:20;:33::i;:::-;106344:119;;;;106478:11;106474:241;;;106506:176;106543:5;106567:4;106590:15;:13;:15::i;:::-;106624;:13;:15::i;:::-;106658:9;106506:18;:176::i;:::-;106697:7;;;;106474:241;106727:27;;:::i;:::-;106782:15;;;;106757:41;;:5;;:41;:24;:41;:::i;:::-;106727:71;;106811:153;106839:23;:10;:21;:23::i;:::-;106838:24;106877:4;106811:153;106938:4;:15;;;106811:12;:153::i;:::-;106992:24;;:::i;:::-;107031;;:::i;:::-;107124:17;;;;107156:15;;;;107186:11;;107069:139;;:5;;107124:17;;107069:139;:40;:139;:::i;:::-;106977:231;;;;107236:31;;:::i;:::-;107282;;:::i;:::-;107327:132;107363:5;107383;107403:4;:15;;;107433:4;:15;;;107327:21;:132::i;:::-;107221:238;;;;107472:24;;:::i;:::-;107499:48;107517:7;107526:9;107537;107499:17;:48::i;:::-;107472:75;;107661:10;:16;;;107645:7;:13;;;:32;107641:477;;;107704:21;:10;:19;:21::i;:::-;107694:31;;107750:48;107768:7;107777:9;107788;107750:17;:48::i;:::-;107858:17;;;;107894:15;;;;107740:58;;-1:-1:-1;107815:135:0;;:5;;107858:17;107740:58;107815:135;:24;:135;:::i;:::-;107641:477;;;108014:17;;;;108050:15;;;;107983:123;;:5;;108084:7;107983:123;:12;:123;:::i;:::-;108181:130;108220:4;:17;;;108252:4;:15;;;108282:18;:7;:16;:18::i;:::-;108181:5;;:130;;;:24;:130;:::i;:::-;108322;108361:4;:17;;;108393:4;:15;;;108423:18;:7;:16;:18::i;108322:130::-;108465:136;108498:5;108518:4;108537:7;108559;108581:9;108465:18;:136::i;:::-;105592:3017;;;;;;;;;;;:::o;34535:394::-;34689:15;;:::i;:::-;34748;34729;;:34;;;;;;;;;34722:42;;;;34782:139;;;;;;;;34815:8;34824:4;:14;;;34815:24;;;;;;;;;;;;;;34782:139;;;;34862:4;:17;;;34782:139;;;;;;34900:4;:9;;;34782:139;;;34775:146;;34535:394;;;;:::o;108617:355::-;108773:12;;108749:49;;:5;;108787:10;108749:49;:23;:49;:::i;:::-;108819:11;;;;108884:12;;108911:9;;;;;108811:120;;;;;:33;;;;;;;:120;;108859:10;;108811:120;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;108811:120:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;108811:120:0;;;;108944:20;108959:4;108944:14;:20::i;:::-;108617:355;;:::o;37042:175::-;37189:13;:20;;37042:175::o;37448:211::-;37589:4;37618:5;:13;;;37632:8;37618:23;;;;;;;;;;;;;;:33;;;37611:40;;37448:211;;;;:::o;37895:214::-;38036:7;38068:5;:13;;;38082:8;38068:23;;;;;;;;;;;;;;:33;;;38061:40;;37895:214;;;;:::o;54905:229::-;55048:21;;:::i;:::-;-1:-1:-1;55094:23:0;;;;:13;;;;:23;;;;;;;;;55087:39;;;;;;;;55094:32;;;55087:39;;;;;;;;;;;;;;;;54905:229;;;;:::o;60782:1085::-;61014:4;61107:33;;:::i;:::-;61155;;:::i;:::-;61202:71;:5;61225:7;61234:5;61268:4;61202:71;:22;:71;:::i;:::-;61290:17;;61092:181;;-1:-1:-1;61092:181:0;-1:-1:-1;61286:66:0;;61336:4;61329:11;;;;;;61286:66;61368:16;61364:320;;;61453:33;;;:39;61432:17;;61575:13;;61607:14;;;;61401:271;;61432:60;;;;61511:4;;61401:271;;61575:13;;61401:12;:271::i;:::-;61733:17;;61721:60;;;;;;;;;61752:16;;;61721:60;;;61696:22;;61721:60;;:11;:60::i;:::-;61822:17;;61696:85;;-1:-1:-1;61822:37:0;;61696:85;61822:37;:21;:37;:::i;:::-;61801:11;:17;;;:58;;61794:65;;;;;60782:1085;;;;;;;:::o;5668:671::-;5864:4;5859:473;;5982:15;5992:4;5982:9;:15::i;:::-;6024:5;6056:17;6066:6;6056:9;:17::i;:::-;6100:6;6133:19;6143:8;6133:9;:19::i;56191:251::-;56397:13;;56382:29;;56343:14;56382:29;;;:14;;;;;:29;;;;;;;;56412:14;;;;56382:45;;;;;;;:52;;;;;;56191:251::o;67245:237::-;67428:13;;67413:29;;;;;;:14;;;;:29;;;;;;;;67443:14;;;;67413:45;;;;;;;;:52;;;;:61;;67468:6;;67413:52;;:61;;;;;67468:6;;67413:61;;;;;;;;;;;;67245:237;;;:::o;7185:988::-;7284:12;7362:19;7401:5;7384:23;;;;;;;;;;;;;22:32:-1;26:21;;;22:32;6:49;;7384:23:0;;;;-1:-1:-1;49:4;7516:587:0;7537:5;;7516:587;;7794:9;;7693:3;;;;;7794:6;;7693:3;;7794:9;;;;;;;;;;;;;;;;;:14;;;7790:302;;7850:1;7846:5;7980:22;;7987:6;-1:-1:-1;8063:13:0;;7790:302;7516:587;;;-1:-1:-1;8153:12:0;;;8163:1;8153:12;;;;;;;;;;;-1:-1:-1;8146:19:0;7185:988;-1:-1:-1;;;7185:988:0:o;8181:949::-;8280:12;8314:10;8310:53;;-1:-1:-1;8341:10:0;;;;;;;;;;;;;;;;;;;8310:53;8427:5;8415:9;8468:72;8475:6;;8468:72;;8498:8;;8526:2;8521:7;;;;8468:72;;;8584:17;8614:6;8604:17;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;104:10;8604:17:0;87:34:-1;135:17;;-1:-1;8604:17:0;-1:-1:-1;8716:5:0;;-1:-1:-1;8584:37:0;-1:-1:-1;8749:6:0;8732:367;8757:5;;8732:367;;8913:3;;9012:2;9008:1;:6;3003:2;8994:21;8983:34;;8973:4;8978:1;8973:7;;;;;;;;;;;:44;;;;;;;;;;-1:-1:-1;9085:2:0;9080:7;;;;8732:367;;;-1:-1:-1;9118:4:0;8181:949;-1:-1:-1;;;;8181:949:0:o;36414:567::-;36590:4;36616:25;:5;36632:8;36616:25;:15;:25;:::i;:::-;36612:70;;;-1:-1:-1;36665:5:0;36658:12;;36612:70;36724:26;:5;36741:8;36724:26;:16;:26;:::i;:::-;36692:13;;:23;;36706:8;;36692:23;;;;;;;;;;;;;;;;;:29;;;;:58;;;;36765:23;;;;:13;;;:23;;;;:33;;;;;36761:191;;;36851:4;36815:5;:13;;;36829:8;36815:23;;;;;;;;;;;;;;;;;;:40;;;;;36906:27;:5;36924:8;36906:27;:17;:27;:::i;:::-;:34;36870:13;;:23;;36884:8;;36870:23;;;;;;;;;;;;;;;;;:70;;;;:33;;:70;36761:191;-1:-1:-1;36969:4:0;36414:567;;;;;:::o;66828:409::-;66957:21;;:::i;:::-;66996:27;;:::i;:::-;67026:24;:5;67041:8;67026:24;:14;:24;:::i;:::-;66996:54;;67085:18;:16;:18::i;:::-;67065:38;;:5;:16;;;:38;;;67061:83;;;67127:5;-1:-1:-1;67120:12:0;;67061:83;67193:36;:5;67213:8;67223:5;67193:36;:19;:36;:::i;:::-;67161:23;;;;:13;;;;;:23;;;;;;;;;:68;;:29;;;;:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67154:75;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;67154:75:0;;66828:409;-1:-1:-1;66828:409:0:o;72535:211::-;72699:8;72670:68;72722:5;72670:68;;;;;;;;;;;;;;;72535:211;;:::o;62347:514::-;62532:20;62580:7;:13;;;62568:25;;:8;:25;;;:74;;;-1:-1:-1;62610:32:0;:5;62633:8;62610:32;:22;:32;:::i;:::-;62568:137;;;-1:-1:-1;62681:13:0;;62659:46;;:5;;62696:8;62659:46;:21;:46;:::i;:::-;62532:173;;62718:135;62745:15;62775:4;62718:135;62834:8;5094:566;5263:4;5258:395;;5381:15;5391:4;5381:9;:15::i;:::-;5423:5;5455:17;5465:6;5455:9;:17::i;:::-;5499:6;5532:19;5542:8;5532:9;:19::i;63016:1501::-;63248:16;;:::i;:::-;63266;;:::i;:::-;63300:23;;:::i;:::-;63326:31;:5;63339:7;63348:8;63326:31;:12;:31;:::i;:::-;63300:57;;63374:6;:12;;;63390:1;63374:17;:61;;;;-1:-1:-1;63409:26:0;63395:6;:10;;;:40;;;;;;;;;63374:61;63370:126;;;63460:6;63468:15;:13;:15::i;:::-;63452:32;;;;;;;63370:126;63508:27;;:::i;:::-;63538:24;:5;63553:8;63538:24;:14;:24;:::i;:::-;63508:54;;63573:23;;:::i;:::-;63599:32;63617:6;63625:5;63599:17;:32::i;:::-;63573:58;;63642:23;;:::i;:::-;63676:25;;:::i;:::-;63741:27;63718:6;:19;;;:50;;;;;;;;;63714:758;;;-1:-1:-1;63796:100:0;;;;;;;;;63831:11;;63796:100;;;;63868:12;;;;63796:100;;;;63929:27;63915:6;:10;;;:41;;;;;;;;;63911:113;;;63988:20;:8;64001:6;63988:20;:12;:20;:::i;:::-;63977:31;;63911:113;64047:46;64065:20;:6;64076:8;64065:20;:10;:20;:::i;:::-;64087:5;64047:17;:46::i;:::-;64038:55;;63714:758;;;64160:108;;;;;;;;64195:6;:11;;;64160:108;;;;;;64232:20;:6;:12;;;:18;:20::i;:::-;64160:108;;;;64151:117;-1:-1:-1;64301:26:0;64287:6;:10;;;:40;;;;;;;;;64283:108;;;64357:18;:6;64368;64357:18;:10;:18;:::i;:::-;64348:27;;64283:108;64416:44;64453:6;64416:32;64434:6;64442:5;64416:17;:32::i;:::-;:36;:44;:36;:44;:::i;:::-;64405:55;;63714:758;64492:6;;-1:-1:-1;64500:8:0;-1:-1:-1;;;;63016:1501:0;;;;;;;;:::o;67490:1089::-;67684:23;;:::i;:::-;67710:31;:5;67723:7;67732:8;67710:31;:12;:31;:::i;:::-;67684:57;;67758:28;67771:6;67779;67758:12;:28::i;:::-;67754:67;;;67803:7;;;67754:67;67860:30;;:::i;:::-;67893:27;:5;67911:8;67893:27;:17;:27;:::i;:::-;67966:11;;67860:60;;-1:-1:-1;67962:213:0;;;68012:50;:42;68041:6;:12;;;68012:42;;68020:8;:15;;;68012:24;;:28;;:42;;;;:::i;:::-;:48;:50::i;:::-;67994:68;;:15;;;:68;67962:213;;;68142:12;;;;68121:15;;68113:50;;:42;;;:24;;;;:42;;:28;:42;:::i;:50::-;68095:68;;;;67962:213;68223:11;;68219:213;;;68269:50;:42;68298:6;:12;;;68269:42;;68277:8;:15;;;68269:24;;:28;;:42;;;;:::i;:50::-;68251:68;;:15;;;:68;68219:213;;;68399:12;;;;68378:15;;68370:50;;:42;;;:24;;;;:42;;:28;:42;:::i;:50::-;68352:68;;;;68219:213;68444:23;;;;:13;;;;:23;;;;;;;;:43;;:32;;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68513:13;;68498:29;;;;:14;;;:29;;;;;68528:14;;;;68498:45;;;;;;;:64;;;;;;;:73;;;;;;;;;;;68444:43;68498:73;;;;;;;;;;;;;;;;;;;;-1:-1:-1;67490:1089:0;;;;:::o;54688:209::-;54828:7;54860:23;;;:13;;;;;:23;;;;;:29;;;;54688:209::o;83799:441::-;83943:151;83971:21;:8;:19;:21::i;:::-;83970:22;84007:4;83943:151;84069:8;:14;;;83943:12;:151::i;:::-;84107:125;84140:5;84160:4;84187;84207:8;:14;;;84107:18;:125::i;72857:486::-;73064:12;;;;;:18;;73097:19;;;;73131:11;;;;73039:296;;;;;;;73157:143;;73192:5;;73131:11;73277:8;73157:16;:143::i;:::-;73315:4;:9;;;73039:296;;;;;;;;;;;;;;;;;;72857:486;;;:::o;83384:407::-;83527:152;83555:21;:8;:19;:21::i;:::-;83554:22;83591:4;83527:152;83654:8;:14;;;83527:12;:152::i;:::-;83692:91;83721:5;83741:2;83758:8;:14;;;83692;:91::i;73351:487::-;73561:12;;;;;:18;;73594:19;;;;73628:11;;;;73535:295;;;;;;;73654:143;;73689:5;;73628:11;73774:8;73654:16;:143::i;17614:214::-;17712:10;;:::i;:::-;-1:-1:-1;17747:73:0;;;;;;;;;17773:6;;17772:7;17747:73;;;17801:7;;;;17747:73;;;;17614:214;;;:::o;68677:630::-;68889:17;:8;:15;:17::i;:::-;68885:56;;;68923:7;;68885:56;68951:27;;:::i;:::-;68981:24;:5;68996:8;68981:24;:14;:24;:::i;:::-;68951:54;;69016:23;;:::i;:::-;69042:31;:5;69055:7;69064:8;69042:31;:12;:31;:::i;:::-;69016:57;;69084:23;;:::i;:::-;69110:20;:6;69121:8;69110:20;:10;:20;:::i;:::-;69084:46;;69141:23;;:::i;:::-;69167:32;69185:6;69193:5;69167:17;:32::i;:::-;69141:58;-1:-1:-1;69210:89:0;:5;69237:7;69259:8;69141:58;69210:89;:12;:89;:::i;73846:719::-;74129:15;;;;:21;;74056:15;;;;;:21;;74092:22;;;;74165;;;;;74202:11;;;;74030:527;;;;;;;;;;;74092:22;74228:146;;74263:5;;74202:11;74351:8;74228:16;:146::i;:::-;74389:157;74424:5;74448:4;:15;;;74482:4;:11;;;74512:19;:8;:17;:19::i;:::-;74389:16;:157::i;:::-;74030:527;;;;;;;;;;;;;;;;;;;73846:719;;;:::o;84248:730::-;84490:16;;:::i;:::-;84524:158;84552:26;:13;:24;:26::i;:::-;84551:27;84593:4;84524:158;84652:13;:19;;;84524:12;:158::i;:::-;84695:23;;:::i;:::-;84743:5;84729:19;;84890;;;;84774:170;;;;;:49;;;;;;:170;;84838:11;;84864;;84890:19;84924:9;;84774:170;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;84774:170:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;84774:170:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;84774:170:0;;;;;;;;;84759:12;;;:185;:6;-1:-1:-1;84248:730:0;;;;;;;;:::o;84986:956::-;85252:16;;:::i;:::-;85286:171;85314:32;:19;:30;:32::i;:::-;85313:33;85361:4;85286:171;85421:19;:25;;;85286:12;:171::i;:::-;85470:62;85482:11;85495:15;85512:19;85470:11;:62::i;:::-;85545:23;;:::i;:::-;85593:4;85579:18;;85787:25;;;;85623:224;;;;;:42;;;;;;:224;;85680:12;;85715:4;;85735:11;;85761;;85787:25;85827:9;;85623:224;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;85623:224:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;85623:224:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;85623:224:0;;;;;;;;;85608:12;;;:239;85860:48;85871:11;85884:15;85608:6;85860:10;:48::i;:::-;85928:6;-1:-1:-1;84986:956:0;;;;;;;;;:::o;74573:725::-;74804:12;;;;;:18;;74837:19;;;;74871:16;;;;74902;;;;74783:507;;;;;;;74933:148;;74968:5;;74871:16;75058:8;74933:16;:148::i;:::-;75096;75131:5;75155:4;:12;;;75186:4;:16;;;75221:8;75096:16;:148::i;:::-;75259:4;:20;;;74783:507;;;;;;;;;;;;;;;;;;;;74573:725;;;;:::o;75306:728::-;75540:12;;;;;:18;;75573:19;;;;75607:16;;;;75638;;;;75518:508;;;;;;;75669:148;;75704:5;;75607:16;75794:8;75669:16;:148::i;:::-;75832;75867:5;75891:4;:12;;;75922:4;:16;;;75957:8;75832:16;:148::i;18169:145::-;18294:7;;;:12;;18169:145::o;76042:1345::-;76252:31;;:::i;:::-;:743;;;;;;;;76301:164;76336:5;76360:4;:17;;;76396:4;:16;;;76431:19;:8;:17;:19::i;76301:164::-;76252:743;;;;76480:166;76515:5;76539:4;:17;;;76575:4;:17;;;76611:20;:9;:18;:20::i;76480:166::-;76252:743;;;;76661:153;76696:5;76720:4;:17;;;76756:4;:16;;;76791:8;76661:16;:153::i;:::-;76252:743;;;;76829:155;76864:5;76888:4;:17;;;76924:4;:17;;;76960:9;76829:16;:155::i;:::-;76252:743;;77113:17;;;;:23;;77036:17;;;;;:23;;77074:24;;;;77151;;;;;77190:16;;;;77221:17;;;;76252:743;;-1:-1:-1;77013:366:0;;;;;;;;;;;;76252:743;77113:23;77253:10;;;;77278:7;77286:1;77278:10;;;;77303:7;77311:1;77303:10;;;;77328:7;77336:1;77328:10;;;;77353:4;:15;;;77013:366;;;;;;;;;;;;;;;;;;;;;;;76042:1345;;;;;:::o;56747:465::-;56923:16;;:::i;:::-;56957:20;;:::i;:::-;56980:31;:5;56993:7;57002:8;56980:31;:12;:31;:::i;:::-;56957:54;;57028:12;:3;:10;:12::i;:::-;57024:67;;;57064:15;:13;:15::i;:::-;57057:22;;;;;57024:67;57103:27;;:::i;:::-;57133:24;:5;57148:8;57133:24;:14;:24;:::i;:::-;57103:54;;57175:29;57193:3;57198:5;57175:17;:29::i;17836:159::-;17966:6;;17936:4;;17965:7;:22;;;;-1:-1:-1;;17976:7:0;;;:11;;;17836:159::o;6347:776::-;6570:4;6565:551;;6688:15;6698:4;6688:9;:15::i;:::-;6730:5;6762:17;6772:6;6762:9;:17::i;:::-;6806:6;6839:19;6849:8;6839:9;:19::i;:::-;6885:5;6917:19;6927:8;6917:9;:19::i;:::-;6963:5;6995:19;7005:8;6995:9;:19::i;:::-;6645:425;;;;;;;;;;;;;7041:6;;6645:425;;;;64525:1487;64771:16;;:::i;:::-;64789;;:::i;:::-;64823:23;;:::i;:::-;64849:31;:5;64862:7;64871:8;64849:31;:12;:31;:::i;:::-;64823:57;;64893:205;64921:19;:6;:17;:19::i;:::-;64920:20;64955:4;64893:205;65022:7;:13;;;65050:7;:14;;;65079:8;64893:12;:205::i;:::-;65126:23;;:::i;:::-;65164:25;;:::i;:::-;65203:103;:5;65244:7;65266:8;65289:6;65203:103;:26;:103;:::i;:::-;65111:195;;;;65403:19;:6;:17;:19::i;:::-;65399:144;;;65448:15;:13;:15::i;:::-;65439:24;-1:-1:-1;65489:42:0;:31;:5;65502:7;65511:8;65489:31;:12;:31;:::i;:::-;:40;:42::i;:::-;65478:53;;65399:144;65555:236;65583:21;:8;:19;:21::i;:::-;65582:22;:54;;;;;65624:6;:12;;;65608:28;;:6;:12;;;:28;;;;65582:54;65651:4;65555:236;65715:7;:13;;;65743:7;:14;;;65772:8;65555:12;:236::i;:::-;65891:21;:6;65905;65891:21;:13;:21;:::i;:::-;65887:80;;;65940:15;:13;:15::i;:::-;65929:26;;65887:80;65987:6;;;;-1:-1:-1;64525:1487:0;-1:-1:-1;;;;;;64525:1487:0:o;111850:742::-;112093:21;;:::i;:::-;112129;;:::i;:::-;112178;112202:28;:5;112217:12;112202:28;:14;:28;:::i;:::-;:34;;-1:-1:-1;112247:26:0;;:::i;:::-;112276:98;:5;112324:12;112351;112276:98;:33;:98;:::i;:::-;112247:127;;112387:31;;:::i;:::-;112421:102;;;;;;;;112458:53;112476:34;112488:13;112503:6;112476:11;:34::i;:::-;112458:13;;:53;:17;:53;:::i;:::-;112421:102;;112387:136;-1:-1:-1;112544:28:0;:5;112559:12;112544:28;:14;:28;:::i;:::-;112536:48;112574:9;;-1:-1:-1;111850:742:0;-1:-1:-1;;;;;;;111850:742:0:o;109222:385::-;109424:16;;:::i;:::-;109465:134;;;;;;;;109496:5;109465:134;;;;;;109523:64;109539:7;:13;;;109554:9;:15;;;109571:9;:15;;;109523;:64::i;:::-;109465:134;;109458:141;109222:385;-1:-1:-1;;;;109222:385:0:o;109803:391::-;110005:16;;:::i;:::-;110046:140;;;;;;;;110077:4;110046:140;;;;;;110103:71;110126:7;:13;;;110141:9;:15;;;110158:9;:15;;;110103:22;:71::i;14005:177::-;14074:10;;:::i;:::-;-1:-1:-1;14109:65:0;;;;;;;;;-1:-1:-1;14109:65:0;;;;;;;14005:177;:::o;77624:1341::-;77839:36;;:::i;:::-;77878:142;77909:5;77929:4;:17;;;77961:4;:15;;;77991:18;:7;:16;:18::i;77878:142::-;77839:181;;78031:36;;:::i;:::-;78070:142;78101:5;78121:4;:17;;;78153:4;:15;;;78183:18;:7;:16;:18::i;78070:142::-;78031:181;;78223:37;;:::i;:::-;78263:132;78294:5;78314:4;:18;;;78347:4;:15;;;78377:7;78263:16;:132::i;:::-;78223:172;;78406:37;;:::i;:::-;78446:132;78477:5;78497:4;:18;;;78530:4;:15;;;78560:7;78446:16;:132::i;:::-;78406:172;;78700:4;:18;;;:24;;;78596:361;;78623:4;:17;;;:23;;;78596:361;;;78661:4;:17;;;:24;;;78739:4;:18;;;:25;;;78779:4;:15;;;78809:4;:15;;;78839;78869;78899:16;78930;78596:361;;;;;;;;;;;;;;;;;;;;;;77624:1341;;;;;;;;:::o;66020:741::-;66217:4;;;66295:21;:5;:19;:21::i;:::-;66274:42;-1:-1:-1;66332:9:0;66327:398;66351:10;66347:1;:14;66327:398;;;66388:18;:5;66404:1;66388:18;:15;:18;:::i;:::-;66383:68;;66427:8;;66383:68;66465:20;;:::i;:::-;66488:24;:5;66501:7;66510:1;66488:24;:12;:24;:::i;:::-;66465:47;;66531:12;:3;:10;:12::i;:::-;66527:187;;;66564:8;;;66527:187;66598:8;;66594:120;;;66634:5;66627:12;;;;;;;;66594:120;66694:4;66680:18;;66327:398;;66363:3;;66327:398;;;-1:-1:-1;66742:11:0;;66020:741;-1:-1:-1;;;;;66020:741:0:o;110546:1163::-;110700:4;110706:16;;:::i;:::-;110740:26;;:::i;:::-;110794:15;;;;110769:41;;:5;;:41;:24;:41;:::i;:::-;110740:70;;110879:22;:9;:20;:22::i;:::-;110874:87;;110926:5;110933:15;:13;:15::i;:::-;110918:31;;;;;;;110874:87;110973:29;;:::i;:::-;111018:17;;;;111037:15;;;;111005:48;;:5;;:48;:12;:48;:::i;:::-;111084:4;111064:24;;111188:18;;;;;111169:15;;;;110973:80;;-1:-1:-1;;111165:537:0;;111223:131;111254:4;:17;;;111290:4;:15;;;111324;:13;:15::i;:::-;111223:5;;:131;;;:12;:131;:::i;:::-;111377:4;;-1:-1:-1;111383:12:0;-1:-1:-1;111369:27:0;;-1:-1:-1;111369:27:0;111165:537;111556:17;;;;111592:15;;;;111513:137;;:5;;111626:9;111513:137;:24;:137;:::i;:::-;-1:-1:-1;111673:5:0;;-1:-1:-1;111680:9:0;-1:-1:-1;110546:1163:0;;;;;;:::o;78973:1171::-;79223:36;;:::i;:::-;79262:142;79293:5;79313:4;:17;;;79345:4;:15;;;79375:18;:7;:16;:18::i;79262:142::-;79223:181;;79415:36;;:::i;:::-;79454:142;79485:5;79505:4;:17;;;79537:4;:15;;;79567:18;:7;:16;:18::i;79454:142::-;79415:181;;79607:36;;:::i;:::-;79697:17;;;;79729:15;;;;79646:146;;79677:5;;79759:22;:7;79771:9;79759:22;:11;:22;:::i;79646:146::-;79607:185;;79913:4;:17;;;:23;;;79810:326;;79836:4;:17;;;:23;;;79810:326;;;79874:4;:17;;;:24;;;79951:4;:17;;;:24;;;79990:4;:15;;;80020:4;:15;;;80050;80080;80110;79810:326;;;;;;;;;;;;;55373:810;55523:16;;:::i;:::-;55557:27;;:::i;:::-;55587:24;:5;55602:8;55587:24;:14;:24;:::i;:::-;55557:54;;55622:30;;:::i;:::-;55655:27;:5;55673:8;55655:27;:17;:27;:::i;:::-;55622:60;-1:-1:-1;55695:13:0;55711:24;:5;55726:8;55711:24;:14;:24;:::i;:::-;55695:40;;55748:27;;:::i;:::-;55778:106;;;;;;;;55809:4;55778:106;;;;;;55835:37;55851:5;55866:4;55835:15;:37::i;:::-;55778:106;;55748:136;-1:-1:-1;55912:26:0;;:::i;:::-;55953;;:::i;:::-;55993:39;56016:8;56026:5;55993:22;:39::i;:::-;55897:135;;-1:-1:-1;55897:135:0;-1:-1:-1;56135:40:0;55897:135;56135:25;:10;55897:135;56135:25;:14;:25;:::i;:40::-;56128:47;55373:810;-1:-1:-1;;;;;;;;;55373:810:0:o;77395:221::-;77519:12;;:18;;77552:19;;;;;77586:11;;;;77497:111;;;;;;;;;;;77586:11;77497:111;;;;;;;;;;77395:221;:::o;59474:1300::-;59708:21;;:::i;:::-;59731;;:::i;:::-;59770:33;;:::i;:::-;59814;;:::i;:::-;59860:18;59881:21;:5;:19;:21::i;:::-;59860:42;-1:-1:-1;59918:9:0;59913:808;59937:10;59933:1;:14;59913:808;;;59974:18;:5;59990:1;59974:18;:15;:18;:::i;:::-;59969:68;;60013:8;;59969:68;60053:24;;:::i;:::-;60080;:5;60093:7;60102:1;60080:24;:12;:24;:::i;:::-;60053:51;;60125:16;:7;:14;:16::i;:::-;60121:65;;;60162:8;;;60121:65;60202:18;60223:42;60241:17;:5;60256:1;60241:17;:14;:17;:::i;:::-;:23;60223:13;;;;;:42;:17;:42;:::i;:::-;60202:63;;60280:26;;:::i;:::-;60309:13;:11;:13::i;:::-;60280:42;;60341:18;60337:115;;;60405:16;;;;:13;;;:16;;;;;;;;;60389:47;;;;;;;;60405:30;;;;60389:47;;;;;:15;:47::i;:::-;60380:56;;60337:115;60472:12;;60468:242;;;60525:54;60547:31;60559:10;60571:6;60547:11;:31::i;:::-;60525:17;;;:54;:21;:54;:::i;:::-;60505:74;;60468:242;;;60640:54;60662:31;60674:10;60686:6;60662:11;:31::i;:::-;60640:17;;;:54;:21;:54;:::i;:::-;60620:74;;60468:242;59913:808;;;;59949:3;;59913:808;;;-1:-1:-1;60741:11:0;;60754;;-1:-1:-1;59474:1300:0;-1:-1:-1;;;;;;59474:1300:0:o;38890:197::-;39009:7;39041:38;39057:6;39065:1;:7;;;38411:6;39041:15;:38::i;2268:150::-;2326:7;2358:5;;;2382:6;;;;2374:15;;;;;9138:993;9420:13;;;9430:2;9420:13;;;9237:12;9420:13;;;;;;9279:14;;;;9237:12;;9420:13;;;21:6:-1;;104:10;9420:13:0;87:34:-1;135:17;;-1:-1;9420:13:0;9398:35;;3003:2;9500:23;;9488:6;9495:1;9488:9;;;;;;;;;;;:35;;;;;;;;;;;3113:3;9546:27;;9534:6;9541:1;9534:9;;;;;;;;;;;:39;;;;;;;;;;-1:-1:-1;9690:9:0;9685:413;9709:2;9705:1;:6;9685:413;;;9800:1;9796:5;;9896:23;3340:3;9901:17;;9896:4;:23::i;:::-;9875:6;9887:5;9882:2;:10;9875:18;;;;;;;;;;;:44;;;;;;;;;;-1:-1:-1;45:20;25:41;;;;10038:23:0;3340:3;10043:17;;10038:4;:23::i;:::-;10017:6;10029:5;10024:2;:10;10017:18;;;;;;;;;;;:44;;;;;;;;;;-1:-1:-1;;45:20;25:41;;;;9713:3:0;;9685:413;;58957:509;59099:21;;:::i;:::-;59138:19;59173:23;;;:13;;;:23;;;;;:35;;;;;59220:27;;:::i;:::-;59250:15;;;;59266:24;:5;59281:8;59266:24;:14;:24;:::i;:::-;59250:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59250:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59250:41:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;59250:41:0;;;;;;;;;59329:11;;59220:71;;-1:-1:-1;59302:133:0;;59329:16;;59360:4;59302:133;59416:8;59302:12;:133::i;55142:223::-;55282:21;;:::i;:::-;-1:-1:-1;55328:23:0;;;;:13;;;;;:23;;;;;;;;;55321:36;;;;;;;55328:29;;;;55321:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55142:223::o;39564:138::-;39637:6;39668:26;39678:15;39668:9;:26::i;:::-;39661:33;;39564:138;:::o;57793:480::-;57976:21;;:::i;:::-;58015:25;;:::i;:::-;58043:40;:5;58067:8;58077:5;58043:40;:23;:40;:::i;:::-;58015:68;-1:-1:-1;58103:162:0;58144:5;58015:68;58183:27;:5;58201:8;58183:27;:17;:27;:::i;:::-;58103:162;;;;;;;;;58225:29;;;58103:162;;;:26;:162::i;61875:216::-;62052:31;;62023:4;62052:31;;;:21;;;;;:31;;;;;;;;;61875:216::o;62099:240::-;62299:22;;;;62270:4;62299:22;;;:15;;;;;:22;;;;;;;;:32;;;;;;;;;;;;;62099:240::o;42807:572::-;42944:16;;:::i;:::-;43007:11;;;;43034:10;;42999:20;;;;;43030:342;;;43068:122;;;;;;;;;43103:4;43068:122;;;43155:12;;;;43068:122;;;;43133:41;;:10;;:41;;40078:6;43133:41;:21;:41;:::i;:::-;43068:122;;;43061:129;;;;;43030:342;43230:130;;;;;;;;;-1:-1:-1;43230:130:0;;43325:12;;43230:130;;;;43296:48;;:10;;:48;;40078:6;43296:48;:28;:48;:::i;16457:178::-;16573:10;;:::i;:::-;16608:19;16612:1;16615:11;16624:1;16615:8;:11::i;:::-;16759:10;;:::i;:::-;16787:17;;:::i;:::-;16829:6;;16819;;:16;;;;;;16815:429;;;16866:6;;16852:20;;;;16915:7;;;;;16924;;;;16902:30;;16915:7;16902:12;:30::i;:::-;16887:12;;;:45;16815:429;;;16980:1;:7;;;16969:1;:7;;;:18;16965:268;;17022:6;;17008:20;;;;17075:7;;;;;17084;;;;17062:30;;17075:7;17062:12;:30::i;16965:268::-;17147:6;;17133:20;;;;17200:7;;;;;17209;;;;17187:30;;17200:7;17187:12;:30::i;:::-;17172:12;;;:45;:12;16643:632;-1:-1:-1;;;16643:632:0:o;43473:538::-;43610:16;;:::i;:::-;43648:10;;43644:360;;;43682:131;;;;;;;;43717:4;43682:131;;;;;;43747:50;:42;40078:6;43747:42;;43776:5;:12;;;43747:42;;:5;:11;;;:22;;:42;;;;;:::i;:50::-;43682:131;;;;43675:138;-1:-1:-1;43675:138:0;;43644:360;43853:139;;;;;;;;;-1:-1:-1;43853:139:0;;43955:12;;43853:139;43919:11;;;;43853:139;;;;43919:57;;:49;;40078:6;;43919:49;;;:29;:49;:::i;11643:309::-;11740:7;11790:6;11808:112;11835:16;;;;;11866:4;11808:112;:12;:112::i;14376:656::-;14492:10;;:::i;:::-;14520:17;;:::i;:::-;14562:6;;14552;;:16;;;;;;14548:453;;;14599:6;;14585:20;;;;14648:7;;;;;14657;;;;14635:38;;:30;;;;;;;;:12;:30::i;:38::-;14620:53;;:12;;;:53;14548:453;;;14721:1;:7;;;14710:18;;:1;:7;;;:18;;;14706:284;;14763:6;;14749:20;;;;14816:7;;;;;14825;;;;14803:38;;:30;;;;;;;;:12;:30::i;14706:284::-;14896:6;;14882:20;;;;14949:7;;;;;14958;;;;14936:38;;:30;;;;;;;;:12;:30::i;:38::-;14921:53;;:12;;;:53;:12;14376:656;-1:-1:-1;;;14376:656:0:o;15040:323::-;15159:4;15196:1;:7;;;15185:18;;:1;:7;;;:18;;;15181:152;;;15224:7;;;;:12;;15220:64;;-1:-1:-1;15264:4:0;15257:11;;15220:64;-1:-1:-1;15315:6:0;;15305;;:16;;;;;;15298:23;;15181:152;-1:-1:-1;15350:5:0;15040:323;;;;:::o;2032:150::-;2090:7;2123:1;2118;:6;;2110:15;;;;;;-1:-1:-1;2148:5:0;;;2032:150::o;48153:404::-;48313:11;;;:25;;;48334:4;48328:10;;:2;:10;;;48313:25;48309:64;;;48355:7;;48309:64;48385:44;;;;;:26;;;;;;:44;;48412:4;;48418:2;;48422:6;;48385:44;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;48385:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;48385:44:0;;;;48442:107;48469:14;:12;:14::i;:::-;48498:4;48442:107;:12;:107::i;80206:383::-;80425:20;;:::i;:::-;80470:111;;;;;;;;;;;;;;;80540:29;:5;80553:7;80562:6;80540:29;:12;:29;:::i;:::-;80470:111;;80463:118;80206:383;-1:-1:-1;;;;;80206:383:0:o;18003:158::-;18132:6;;18103:4;;18132:21;;;;-1:-1:-1;;18142:7:0;;;:11;;;18003:158::o;47773:372::-;47906:11;;;:34;;-1:-1:-1;47921:19:0;;;47935:4;47921:19;47906:34;47902:73;;;47957:7;;47902:73;47987:34;;;;;:22;;;;;;:34;;48010:2;;48014:6;;47987:34;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;47987:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;47987:34:0;;;;48034:103;48061:14;:12;:14::i;:::-;48090:4;48034:103;:12;:103::i;15760:158::-;15889:6;;15860:4;;15889:21;;;;-1:-1:-1;;15899:7:0;;;:11;;;;;15760:158::o;37667:220::-;37804:21;;:::i;:::-;37850:13;;:23;;37864:8;;37850:23;;;;;;;;;;;;:29;;;37843:36;;37667:220;;;;:::o;57220:565::-;57414:19;;:::i;:::-;57468:34;;;;:40;57451:14;57564:27;;;57468:34;57564:13;;:27;;;;;;;;;57548:58;;;;;;;;57564:41;;57548:58;;;57468:40;57528:79;;57468:40;;57548:58;;:15;:58::i;:::-;57528:11;:79::i;:::-;57519:88;;57627:79;57639:6;57647:58;57663:5;:13;;:27;57677:12;57663:27;;;;;;;;;;;:41;;57647:58;;;;;;;;;;;;;;;;;:15;:58::i;57627:79::-;57724:53;;;;;;;;;;;;;57220:565;-1:-1:-1;;;;;57220:565:0:o;10882:238::-;11042:7;11074:38;11100:11;11074:21;:6;11085:9;11074:21;:10;:21;:::i;:::-;:25;:38;:25;:38;:::i;11212:423::-;11379:7;11408:11;;;:29;;-1:-1:-1;11423:14:0;;11408:29;11404:154;;;11518:28;11531:1;11534:11;11518:12;:28::i;:::-;11511:35;;;;11404:154;11575:52;11625:1;11575:45;11608:11;11575:28;11625:1;11575:21;:6;11586:9;11575:21;:10;:21;:::i;:::-;:25;:28;:25;:28;:::i;:45::-;:49;:52;:49;:52;:::i;46819:194::-;46975:30;;;;;46943:7;;46975:23;;;;;;:30;;46999:5;;46975:30;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;46975:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;46975:30:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;46975:30:0;;;;;;;;44160:620;44310:16;;:::i;:::-;44328;;:::i;:::-;44362:26;;:::i;:::-;-1:-1:-1;44391:84:0;;;;;;;;;44422:4;44391:84;;;44448:15;;;;44391:84;;;;;;44486:26;;:::i;:::-;-1:-1:-1;44515:85:0;;;;;;;;;-1:-1:-1;44515:85:0;;44573:15;;44515:85;;;;;;44611:26;;:::i;:::-;44640;44649:9;44660:5;44640:8;:26::i;:::-;44611:55;;44677:26;;:::i;:::-;44706;44715:9;44726:5;44706:8;:26::i;:::-;44751:9;;;;-1:-1:-1;44160:620:0;;-1:-1:-1;;;;;;44160:620:0:o;1027:433::-;1085:7;1329:6;1325:47;;-1:-1:-1;1359:1:0;1352:8;;1325:47;1396:5;;;1400:1;1396;:5;:1;1420:5;;;;;:10;1412:19;;;;;38568:130;38633:11;;:::i;:::-;-1:-1:-1;38669:21:0;;;;;;;;;38411:6;38669:21;;38568:130;:::o;38706:176::-;38804:11;;:::i;:::-;38840:34;;;;;;;;;38854:7;;38840:34;;38854:17;;38411:6;38854:17;:11;:17;:::i;:::-;38840:34;;38833:41;38706:176;-1:-1:-1;;38706:176:0:o;39095:197::-;39214:7;39246:38;39262:6;38411;39276:1;:7;;;39246:15;:38::i;10139:339::-;10233:4;10304:2;10296:5;:10;10292:81;;;-1:-1:-1;10330:31:0;3003:2;10341:18;;10330:31;10323:38;;10292:81;-1:-1:-1;3058:2:0;10441:27;10430:40;;;10139:339::o;12272:304::-;12368:6;12415;12433:111;12460:16;;;;;12491:4;12433:111;:12;:111::i;58281:668::-;58468:20;;:::i;:::-;58506:30;;:::i;:::-;58539:27;:5;58557:8;58539:27;:17;:27;:::i;:::-;58506:60;;58592:26;;:::i;:::-;58633;;:::i;:::-;58673:39;58696:8;58706:5;58673:22;:39::i;:::-;58577:135;;;;58725:25;;:::i;:::-;58753:23;;;;:13;;;:23;;;;;:38;;;;;:54;58822:24;58753:5;58767:8;58822:24;:14;:24;:::i;:::-;58861:9;:15;;;58891:9;:15;;;58753:164;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58753:164:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;58753:164:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;58753:164:0;;;;;;;;;58725:192;58281:668;-1:-1:-1;;;;;;;;58281:668:0:o;41138:1335::-;41362:12;;:::i;:::-;41407:26;;:::i;:::-;41448;;:::i;:::-;41488:30;41502:8;41512:5;41488:13;:30::i;:::-;41392:126;;;;41579:18;41600;:16;:18::i;:::-;41579:39;;41629:22;41654:58;41669:42;41694:5;:16;;;41669:42;;41677:11;41669:20;;:24;;:42;;;;:::i;:::-;41654:10;;;:58;:14;:58;:::i;:::-;41629:83;;41773:22;41810:23;41823:9;41810:12;:23::i;:::-;41806:335;;;-1:-1:-1;41867:1:0;41806:335;;;41918:41;41930:14;41946:12;41918:11;:41::i;:::-;41901:58;;41996:9;:15;;;41978:9;:15;;;:33;41974:156;;;42049:65;42065:14;42081:9;:15;;;42098:9;:15;;;42049;:65::i;:::-;42032:82;;41974:156;42176:14;42158;:32;;42151:40;;;;42211:254;;;;;;;;;42296:12;;42211:254;;42240:76;;:69;;;;:51;:69;42270:14;40078:6;42240:15;:51::i;:69::-;:74;:76::i;:::-;42211:254;;;;;;;42395:12;;;;42211:254;;;42339:76;;:69;;;:51;:69;42369:14;40078:6;42339:15;:51::i;:76::-;42211:254;;;;;;42442:11;42211:254;;;;;42204:261;;;;;;;41138:1335;;;;;;:::o;48806:888::-;48885:4;;49113:14;49193:59;;;;49326:4;49321:226;;;;49106:534;;49193:59;49236:1;49221:16;;49193:59;;49321:226;49428:4;49423:3;49418;49403:30;49528:3;49522:10;49507:25;;49106:534;-1:-1:-1;49670:16:0;;;-1:-1:-1;48806:888:0;:::o;1593:303::-;1651:7;1750:1;1746;:5;1738:14;;;;;;1763:9;1779:1;1775;:5;;;;;;;1593:303;-1:-1:-1;;;;1593:303:0:o;11960:304::-;12056:6;12103;12121:111;12148:16;;;;;12179:4;12121:111;:12;:111::i;86092:26503::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;86092:26503:0;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;86092:26503:0;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;86092:26503:0;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;86092:26503:0;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;86092:26503:0;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;5:118:-1:-;;72:46;110:6;97:20;72:46;;166:750;;307:3;300:4;292:6;288:17;284:27;274:2;;325:1;322;315:12;274:2;362:6;349:20;384:104;399:88;480:6;399:88;;;384:104;;;516:21;;;560:4;548:17;;;;375:113;;-1:-1;573:14;;548:17;668:1;653:257;678:6;675:1;672:13;653:257;;;761:3;748:17;740:6;736:30;785:61;842:3;830:10;785:61;;;773:74;;-1:-1;870:4;861:14;;;;889;;;;;700:1;693:9;653:257;;;657:14;267:649;;;;;;;;954:761;;1089:3;1082:4;1074:6;1070:17;1066:27;1056:2;;1107:1;1104;1097:12;1056:2;1144:6;1131:20;1166:98;1181:82;1256:6;1181:82;;1166:98;1157:107;;1281:5;1306:6;1299:5;1292:21;1336:4;1328:6;1324:17;1314:27;;1358:4;1353:3;1349:14;1342:21;;1411:6;1458:3;1450:4;1442:6;1438:17;1433:3;1429:27;1426:36;1423:2;;;1475:1;1472;1465:12;1423:2;1500:1;1485:224;1510:6;1507:1;1504:13;1485:224;;;1568:3;1590:55;1641:3;1629:10;1590:55;;;1578:68;;-1:-1;1669:4;1660:14;;;;1697:4;1688:14;;;;;1532:1;1525:9;1485:224;;1723:112;;1787:43;1822:6;1809:20;1787:43;;1842:116;;1917:36;1945:6;1939:13;1917:36;;1966:432;;2063:3;2056:4;2048:6;2044:17;2040:27;2030:2;;2081:1;2078;2071:12;2030:2;2118:6;2105:20;2140:60;2155:44;2192:6;2155:44;;2140:60;2131:69;;2220:6;2213:5;2206:21;2256:4;2248:6;2244:17;2289:4;2282:5;2278:16;2324:3;2315:6;2310:3;2306:16;2303:25;2300:2;;;2341:1;2338;2331:12;2300:2;2351:41;2385:6;2380:3;2375;2351:41;;;2023:375;;;;;;;;2406:148;;2488:61;2541:6;2528:20;2488:61;;2561:160;;2649:67;2708:6;2695:20;2649:67;;2728:164;;2827:60;2879:6;2873:13;2827:60;;3257:1521;;3370:5;3358:9;3353:3;3349:19;3345:31;3342:2;;;3389:1;3386;3379:12;3342:2;3407:21;3422:5;3407:21;;;3398:30;-1:-1;3484:1;3515:64;3575:3;3555:9;3515:64;;;3491:89;;-1:-1;3646:2;3679:49;3724:3;3700:22;;;3679:49;;;3672:4;3665:5;3661:16;3654:75;3601:139;3792:2;3825:73;3894:3;3885:6;3874:9;3870:22;3825:73;;;3818:4;3811:5;3807:16;3800:99;3750:160;3971:3;4005:49;4050:3;4041:6;4030:9;4026:22;4005:49;;;3998:4;3991:5;3987:16;3980:75;3920:146;4129:3;4163:49;4208:3;4199:6;4188:9;4184:22;4163:49;;;4156:4;4149:5;4145:16;4138:75;4076:148;4282:3;4316:49;4361:3;4352:6;4341:9;4337:22;4316:49;;;4309:4;4302:5;4298:16;4291:75;4234:143;4437:3;4471:49;4516:3;4507:6;4496:9;4492:22;4471:49;;;4464:4;4457:5;4453:16;4446:75;4387:145;4610:3;4599:9;4595:19;4582:33;4635:18;4627:6;4624:30;4621:2;;;4667:1;4664;4657:12;4621:2;4702:54;4752:3;4743:6;4732:9;4728:22;4702:54;;;4695:4;4688:5;4684:16;4677:80;4542:226;3336:1442;;;;;4816:797;;4929:4;4917:9;4912:3;4908:19;4904:30;4901:2;;;4947:1;4944;4937:12;4901:2;4965:20;4980:4;4965:20;;;4956:29;-1:-1;5035:1;5066:46;5108:3;5088:9;5066:46;;;5042:71;;-1:-1;5182:2;5215:70;5281:3;5257:22;;;5215:70;;;5208:4;5201:5;5197:16;5190:96;5134:163;5346:2;5379:67;5442:3;5433:6;5422:9;5418:22;5379:67;;;5372:4;5365:5;5361:16;5354:93;5307:151;5509:2;5542:49;5587:3;5578:6;5567:9;5563:22;5542:49;;;5535:4;5528:5;5524:16;5517:75;5468:135;4895:718;;;;;5651:856;;5779:4;5767:9;5762:3;5758:19;5754:30;5751:2;;;5797:1;5794;5787:12;5751:2;5815:20;5830:4;5815:20;;;5806:29;-1:-1;5885:1;5916:57;5969:3;5949:9;5916:57;;;5892:82;;-1:-1;6043:2;6076:81;6153:3;6129:22;;;6076:81;;;6069:4;6062:5;6058:16;6051:107;5995:174;6218:2;6251:78;6325:3;6316:6;6305:9;6301:22;6251:78;;;6244:4;6237:5;6233:16;6226:104;6179:162;6392:2;6425:60;6481:3;6472:6;6461:9;6457:22;6425:60;;6540:462;;6647:4;6635:9;6630:3;6626:19;6622:30;6619:2;;;6665:1;6662;6655:12;6619:2;6683:20;6698:4;6683:20;;;6674:29;-1:-1;6754:1;6785:49;6830:3;6810:9;6785:49;;;6761:74;;-1:-1;6898:2;6931:49;6976:3;6952:22;;;6931:49;;;6924:4;6917:5;6913:16;6906:75;6856:136;6613:389;;;;;7037:343;;7160:4;7148:9;7143:3;7139:19;7135:30;7132:2;;;7178:1;7175;7168:12;7132:2;7196:20;7211:4;7196:20;;;7187:29;-1:-1;7267:1;7298:60;7354:3;7334:9;7298:60;;;7274:85;;-1:-1;7285:5;7126:254;-1:-1;;7126:254;7763:166;;7854:70;7916:6;7903:20;7854:70;;8061:122;;8139:39;8170:6;8164:13;8139:39;;8190:320;;8333:3;8321:9;8312:7;8308:23;8304:33;8301:2;;;8350:1;8347;8340:12;8301:2;8385:1;8402:92;8486:7;8466:9;8402:92;;8517:309;;8655:2;8643:9;8634:7;8630:23;8626:32;8623:2;;;8671:1;8668;8661:12;8623:2;8706:1;8723:87;8802:7;8782:9;8723:87;;9147:895;;;;9401:2;9389:9;9380:7;9376:23;9372:32;9369:2;;;9417:1;9414;9407:12;9369:2;9452:1;9469:77;9538:7;9518:9;9469:77;;;9459:87;;9431:121;9611:2;9600:9;9596:18;9583:32;9635:18;9627:6;9624:30;9621:2;;;9667:1;9664;9657:12;9621:2;9687:96;9775:7;9766:6;9755:9;9751:22;9687:96;;;9677:106;;9562:227;9848:2;9837:9;9833:18;9820:32;9872:18;9864:6;9861:30;9858:2;;;9904:1;9901;9894:12;9858:2;9924:102;10018:7;10009:6;9998:9;9994:22;9924:102;;;9914:112;;9799:233;9363:679;;;;;;10049:263;;10164:2;10152:9;10143:7;10139:23;10135:32;10132:2;;;10180:1;10177;10170:12;10132:2;10215:1;10232:64;10288:7;10268:9;10232:64;;10319:142;10410:45;10449:5;10410:45;;;10405:3;10398:58;10392:69;;;10468:110;10541:31;10566:5;10541:31;;10712:101;10779:28;10801:5;10779:28;;10820:155;10919:50;10938:30;10962:5;10938:30;;;10919:50;;10982:155;11081:50;11100:30;11124:5;11100:30;;11144:159;11245:52;11265:31;11290:5;11265:31;;11310:343;;11420:38;11452:5;11420:38;;;11470:70;11533:6;11528:3;11470:70;;;11463:77;;11545:52;11590:6;11585:3;11578:4;11571:5;11567:16;11545:52;;;11618:29;11640:6;11618:29;;;11609:39;;;;11400:253;-1:-1;;;11400:253;11660:356;;11788:38;11820:5;11788:38;;;11838:88;11919:6;11914:3;11838:88;;;11831:95;;11931:52;11976:6;11971:3;11964:4;11957:5;11953:16;11931:52;;;11995:16;;;;;11768:248;-1:-1;;11768:248;12784:562;13008:22;;12939:4;12930:14;;;13036:99;12934:3;13008:22;13036:99;;;12959:182;13215:4;13208:5;13204:16;13198:23;13227:98;13319:4;13314:3;13310:14;13297:11;13227:98;;14036:622;14242:22;;14175:4;14166:14;;;14270:59;14170:3;14242:22;14270:59;;;14195:140;14409:4;14402:5;14398:16;14392:23;14421:60;14475:4;14470:3;14466:14;14453:11;14421:60;;;14345:142;14565:4;14558:5;14554:16;14548:23;14577:60;14631:4;14626:3;14622:14;14609:11;14577:60;;14714:463;14913:22;;14847:4;14838:14;;;14941:61;14842:3;14913:22;14941:61;;;14867:141;15082:4;15075:5;15071:16;15065:23;15094:62;15150:4;15145:3;15141:14;15128:11;15094:62;;15227:455;15425:22;;15360:4;15351:14;;;15453:55;15355:3;15425:22;15453:55;;;15380:134;15587:4;15580:5;15576:16;15570:23;15599:62;15655:4;15650:3;15646:14;15633:11;15599:62;;16223:457;16423:22;;16358:4;16349:14;;;16451:55;16353:3;16423:22;16451:55;;17180:110;17253:31;17278:5;17253:31;;17297:110;17370:31;17395:5;17370:31;;17541:107;17612:30;17636:5;17612:30;;17655:107;17726:30;17750:5;17726:30;;17769:244;;17888:75;17959:3;17950:6;17888:75;;;-1:-1;17985:2;17976:12;;17876:137;-1:-1;17876:137;18020:553;;18236:93;18325:3;18316:6;18236:93;;;18229:100;;18340:73;18409:3;18400:6;18340:73;;;18435:1;18430:3;18426:11;18419:18;;18455:93;18544:3;18535:6;18455:93;;18580:978;;18894:93;18983:3;18974:6;18894:93;;;18887:100;;18998:73;19067:3;19058:6;18998:73;;;19093:1;19088:3;19084:11;19077:18;;19113:93;19202:3;19193:6;19113:93;;;19106:100;;19217:73;19286:3;19277:6;19217:73;;;19312:1;19307:3;19303:11;19296:18;;19332:93;19421:3;19412:6;19332:93;;;19325:100;;19436:73;19505:3;19496:6;19436:73;;;-1:-1;19531:1;19522:11;;18875:683;-1:-1;;;;;;18875:683;19565:1269;;19951:93;20040:3;20031:6;19951:93;;;19944:100;;20055:73;20124:3;20115:6;20055:73;;;20150:1;20145:3;20141:11;20134:18;;20170:93;20259:3;20250:6;20170:93;;;20163:100;;20274:73;20343:3;20334:6;20274:73;;;20369:1;20364:3;20360:11;20353:18;;20389:93;20478:3;20469:6;20389:93;;;20382:100;;20493:73;20562:3;20553:6;20493:73;;;20588:1;20583:3;20579:11;20572:18;;20608:93;20697:3;20688:6;20608:93;;;20601:100;;20712:73;20781:3;20772:6;20712:73;;;-1:-1;20807:1;20798:11;;19932:902;-1:-1;;;;;;;;19932:902;20841:1560;;21299:93;21388:3;21379:6;21299:93;;;21292:100;;21403:73;21472:3;21463:6;21403:73;;;21498:1;21493:3;21489:11;21482:18;;21518:93;21607:3;21598:6;21518:93;;;21511:100;;21622:73;21691:3;21682:6;21622:73;;;21717:1;21712:3;21708:11;21701:18;;21737:93;21826:3;21817:6;21737:93;;;21730:100;;21841:73;21910:3;21901:6;21841:73;;;21936:1;21931:3;21927:11;21920:18;;21956:93;22045:3;22036:6;21956:93;;;21949:100;;22060:73;22129:3;22120:6;22060:73;;;22155:1;22150:3;22146:11;22139:18;;22175:93;22264:3;22255:6;22175:93;;;22168:100;;22279:73;22348:3;22339:6;22279:73;;;-1:-1;22374:1;22365:11;;21280:1121;-1:-1;;;;;;;;;;21280:1121;22408:213;22526:2;22511:18;;22540:71;22515:9;22584:6;22540:71;;22628:229;22754:2;22739:18;;22768:79;22743:9;22820:6;22768:79;;22864:608;23100:3;23085:19;;23115:79;23089:9;23167:6;23115:79;;;23205:112;23313:2;23302:9;23298:18;23289:6;23205:112;;;23365:9;23359:4;23355:20;23350:2;23339:9;23335:18;23328:48;23390:72;23457:4;23448:6;23390:72;;23479:855;23755:3;23740:19;;23770:71;23744:9;23814:6;23770:71;;;23852:72;23920:2;23909:9;23905:18;23896:6;23852:72;;;23935;24003:2;23992:9;23988:18;23979:6;23935:72;;;24018;24086:2;24075:9;24071:18;24062:6;24018:72;;;24101:73;24169:3;24158:9;24154:19;24145:6;24101:73;;;24223:9;24217:4;24213:20;24207:3;24196:9;24192:19;24185:49;24248:76;24319:4;24310:6;24248:76;;24341:435;24515:2;24500:18;;24529:71;24504:9;24573:6;24529:71;;;24611:72;24679:2;24668:9;24664:18;24655:6;24611:72;;;24694;24762:2;24751:9;24747:18;24738:6;24694:72;;24783:631;25003:3;24988:19;;25018:71;24992:9;25062:6;25018:71;;;25100:72;25168:2;25157:9;25153:18;25144:6;25100:72;;;25183;25251:2;25240:9;25236:18;25227:6;25183:72;;;25303:9;25297:4;25293:20;25288:2;25277:9;25273:18;25266:48;25328:76;25399:4;25390:6;25328:76;;25421:324;25567:2;25552:18;;25581:71;25556:9;25625:6;25581:71;;;25663:72;25731:2;25720:9;25716:18;25707:6;25663:72;;25752:435;25926:2;25911:18;;25940:71;25915:9;25984:6;25940:71;;;26022:72;26090:2;26079:9;26075:18;26066:6;26022:72;;26194:301;26332:2;26346:47;;;26317:18;;26407:78;26317:18;26471:6;26407:78;;26502:305;26666:2;26651:18;;26680:117;26655:9;26770:6;26680:117;;26814:324;26960:2;26945:18;;26974:71;26949:9;27018:6;26974:71;;;27056:72;27124:2;27113:9;27109:18;27100:6;27056:72;;27145:672;27409:3;27394:19;;27424:71;27398:9;27468:6;27424:71;;;27506:72;27574:2;27563:9;27559:18;27550:6;27506:72;;;27589:134;27719:2;27708:9;27704:18;27695:6;27589:134;;;27734:73;27802:3;27791:9;27787:19;27778:6;27734:73;;27824:1476;28354:3;28339:19;;28369:71;28343:9;28413:6;28369:71;;;28451:72;28519:2;28508:9;28504:18;28495:6;28451:72;;;28534:112;28642:2;28631:9;28627:18;28618:6;28534:112;;;28657:113;28765:3;28754:9;28750:19;28741:6;28657:113;;;28781;28889:3;28878:9;28874:19;28865:6;28781:113;;;28905;29013:3;29002:9;28998:19;28989:6;28905:113;;;29029:115;29139:3;29128:9;29124:19;29115:6;29029:115;;;29193:9;29187:4;29183:20;29177:3;29166:9;29162:19;29155:49;29218:72;29285:4;29276:6;29218:72;;;29210:80;28325:975;-1:-1;;;;;;;;;;28325:975;29307:907;29661:3;29646:19;;29676:71;29650:9;29720:6;29676:71;;;29758:72;29826:2;29815:9;29811:18;29802:6;29758:72;;;29841;29909:2;29898:9;29894:18;29885:6;29841:72;;;29924:134;30054:2;30043:9;30039:18;30030:6;29924:134;;;30069:135;30199:3;30188:9;30184:19;30175:6;30069:135;;30221:1019;30603:3;30588:19;;30618:71;30592:9;30662:6;30618:71;;;30700:72;30768:2;30757:9;30753:18;30744:6;30700:72;;;30783;30851:2;30840:9;30836:18;30827:6;30783:72;;;30866:134;30996:2;30985:9;30981:18;30972:6;30866:134;;;31011:135;31141:3;31130:9;31126:19;31117:6;31011:135;;;31157:73;31225:3;31214:9;31210:19;31201:6;31157:73;;;30574:666;;;;;;;;;;31247:1255;31719:3;31704:19;;31734:71;31708:9;31778:6;31734:71;;;31816:72;31884:2;31873:9;31869:18;31860:6;31816:72;;;31899;31967:2;31956:9;31952:18;31943:6;31899:72;;;31982;32050:2;32039:9;32035:18;32026:6;31982:72;;;32065:135;32195:3;32184:9;32180:19;32171:6;32065:135;;;32211;32341:3;32330:9;32326:19;32317:6;32211:135;;;32357;32487:3;32476:9;32472:19;32463:6;32357:135;;32509:1491;33071:3;33056:19;;33086:71;33060:9;33130:6;33086:71;;;33168:72;33236:2;33225:9;33221:18;33212:6;33168:72;;;33251;33319:2;33308:9;33304:18;33295:6;33251:72;;;33334;33402:2;33391:9;33387:18;33378:6;33334:72;;;33417:135;33547:3;33536:9;33532:19;33523:6;33417:135;;;33563;33693:3;33682:9;33678:19;33669:6;33563:135;;;33709;33839:3;33828:9;33824:19;33815:6;33709:135;;;33855;33985:3;33974:9;33970:19;33961:6;33855:135;;34007:1571;34581:3;34566:19;;34596:71;34570:9;34640:6;34596:71;;;34678:72;34746:2;34735:9;34731:18;34722:6;34678:72;;;34761;34829:2;34818:9;34814:18;34805:6;34761:72;;;34844;34912:2;34901:9;34897:18;34888:6;34844:72;;;34927:131;35053:3;35042:9;35038:19;35029:6;34927:131;;;35069;35195:3;35184:9;35180:19;35171:6;35069:131;;;35211;35337:3;35326:9;35322:19;35313:6;35211:131;;;35353;35479:3;35468:9;35464:19;35455:6;35353:131;;;35495:73;35563:3;35552:9;35548:19;35539:6;35495:73;;35585:256;35647:2;35641:9;35673:17;;;35748:18;35733:34;;35769:22;;;35730:62;35727:2;;;35805:1;35802;35795:12;35727:2;35821;35814:22;35625:216;;-1:-1;35625:216;35848:282;;36031:18;36023:6;36020:30;36017:2;;;36063:1;36060;36053:12;36017:2;-1:-1;36092:4;36080:17;;;36110:15;;35954:176;36420:254;;36559:18;36551:6;36548:30;36545:2;;;36591:1;36588;36581:12;36545:2;-1:-1;36664:4;36635;36612:17;;;;36631:9;36608:33;36654:15;;36482:192;36681:87;36751:12;;36735:33;36973:162;37075:19;;;37124:4;37115:14;;37068:67;37468:105;;37537:31;37562:5;37537:31;;37580:92;37653:13;37646:21;;37629:43;37679:151;37758:66;37747:78;;37730:100;37837:151;37916:66;37905:78;;37888:100;37995:79;38064:5;38047:27;38081:120;38161:34;38150:46;;38133:68;38208:128;38288:42;38277:54;;38260:76;38429:95;38508:10;38497:22;;38480:44;38531:111;38610:26;38599:38;;38582:60;38860:135;;38953:1;38946:5;38943:12;38933:2;;38969:1;38966;38959:12;38933:2;-1:-1;38985:5;38927:68;39002:141;;39101:1;39094:5;39091:12;39081:2;;39117:1;39114;39107:12;39626:129;;39713:37;39744:5;39762:121;39841:37;39872:5;39841:37;;40013:145;40094:6;40089:3;40084;40071:30;-1:-1;40150:1;40132:16;;40125:27;40064:94;40167:268;40232:1;40239:101;40253:6;40250:1;40247:13;40239:101;;;40320:11;;;40314:18;40301:11;;;40294:39;40275:2;40268:10;40239:101;;;40355:6;40352:1;40349:13;40346:2;;;-1:-1;;40420:1;40402:16;;40395:27;40216:219;40684:97;40772:2;40752:14;40768:7;40748:28;;40732:49

Swarm Source

bzzr://a49126c145898ce1917c321b14ce2c1922b5f712fcd6e4a142e608deff2da2f9
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

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.