false
false

Contract Address Details

0x3c84B6C98FBeB813e05a7A7813F0442883450B1F

Contract Name
Registry
Creator
0x914dff–98b131 at 0x127239–1f752a
Balance
0 ETH ( )
Tokens
Fetching tokens...
Transactions
64,385 Transactions
Transfers
75,500 Transfers
Gas Used
28,344,305,076
Last Balance Update
57978276
Contract name:
Registry




Optimization enabled
true
Compiler version
v0.8.9+commit.e5eed63a




Optimization runs
200
Verified at
2022-06-22T08:28:32.084711Z

Constructor Arguments

000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000bd67087276ce3263b9333aa337e212a400000000000000000000000000000000000000000000000000000000000000801b0b73f760f5a1fc2d3b14b18a1fb5f7d8e93366ac283423c7b6413dd869bf1300a4398f2222cca7c31cd56b4557249bf9f3c538b30b06e3a9a4c830a9b48feb25fc87924ed7906607d59b6e9555230e73b46378252923ac719a328c7235cb03030e7999862a645112eefee572b4f930a8c66b4141d0f8d76558364ed539c03e

Arg [0] (bytes) : 1b0b73f760f5a1fc2d3b14b18a1fb5f7d8e93366ac283423c7b6413dd869bf1300a4398f2222cca7c31cd56b4557249bf9f3c538b30b06e3a9a4c830a9b48feb25fc87924ed7906607d59b6e9555230e73b46378252923ac719a328c7235cb03030e7999862a645112eefee572b4f930a8c66b4141d0f8d76558364ed539c03e
Arg [1] (uint128) : 251759069107834050899712265849455907492

              

contracts/Registry.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {Integer} from "./libs/Integer.sol";
import {Bytes} from "./libs/Bytes.sol";
import {BLS} from "./libs/BLS.sol";
import {Storage} from "./Storage.sol";
import {IRegistry, Registrable} from "./Registrable.sol";
import {Factory} from "./Factory.sol";
import {Asset} from "./Asset.sol";
import {User} from "./User.sol";

contract Registry is IRegistry, Factory {
    using Bytes for bytes;
    using BLS for uint256[2];
    using BLS for bytes;

    event Halted(bool state);
    event Iterated(uint256[4] from, uint256[4] to);
    event MixinTransaction(bytes raw);
    event MixinEvent(
        uint64 indexed nonce,
        address indexed user,
        address indexed asset,
        uint256 amount,
        bytes extra,
        uint64 timestamp
    );

    uint128 public immutable PID;

    uint256[4] public GROUP;
    uint64 public INBOUND = 0;
    uint64 public OUTBOUND = 0;
    bool public HALTED = false;

    mapping(uint128 => uint256) public balances;

    struct Event {
        uint64 nonce;
        address user;
        address asset;
        uint256 amount;
        bytes extra;
        uint64 timestamp;
        uint256[2] sig;
    }

    constructor(bytes memory raw, uint128 pid) {
        require(raw.length == 128);
        require(pid > 0);
        GROUP = [
            raw.toUint256(0),
            raw.toUint256(32),
            raw.toUint256(64),
            raw.toUint256(96)
        ];
        PID = pid;
    }

    function iterate(bytes memory raw) public {
        require(HALTED, "invalid state");
        require(raw.length == 256, "invalid input size");
        uint256[4] memory group = [
            raw.toUint256(0),
            raw.toUint256(32),
            raw.toUint256(64),
            raw.toUint256(96)
        ];
        uint256[2] memory sig1 = [raw.toUint256(128), raw.toUint256(160)];
        uint256[2] memory sig2 = [raw.toUint256(192), raw.toUint256(224)];
        uint256[2] memory message = raw.slice(0, 128).hashToPoint();
        require(sig1.verifySingle(GROUP, message), "invalid signature");
        require(sig2.verifySingle(group, message), "invalid signature");
        emit Iterated(GROUP, group);
        GROUP = group;
    }

    function halt(bytes memory raw) public {
        bytes memory input = bytes("HALT").concat(
            Integer.uint64ToFixedBytes(INBOUND)
        );
        uint256[2] memory sig = [raw.toUint256(0), raw.toUint256(32)];
        uint256[2] memory message = input.hashToPoint();
        require(sig.verifySingle(GROUP, message), "invalid signature");
        HALTED = !HALTED;
        emit Halted(HALTED);
    }

    function claim(address asset, uint256 amount) external returns (bool) {
        require(users[msg.sender].length > 0, "invalid user");
        require(assets[asset] > 0, "invalid asset");
        Asset(asset).burn(msg.sender, amount);
        sendMixinTransaction(msg.sender, asset, amount, new bytes(0));
        return true;
    }

    function burn(
        address user,
        uint256 amount,
        bytes memory extra
    ) external returns (bool) {
        require(assets[msg.sender] > 0, "invalid asset");
        if (users[user].length == 0) {
            return true;
        }
        Asset(msg.sender).burn(user, amount);
        sendMixinTransaction(user, msg.sender, amount, extra);
        return true;
    }

    function sendMixinTransaction(
        address user,
        address asset,
        uint256 amount,
        bytes memory extra
    ) internal {
        uint256 balance = balances[assets[asset]];
        bytes memory log = buildMixinTransaction(
            OUTBOUND,
            users[user],
            assets[asset],
            amount,
            extra
        );
        emit MixinTransaction(log);
        balances[assets[asset]] = balance - amount;
        OUTBOUND = OUTBOUND + 1;
    }

    // process || nonce || asset || amount || extra || timestamp || members || threshold || sig
    function buildMixinTransaction(
        uint64 nonce,
        bytes memory receiver,
        uint128 asset,
        uint256 amount,
        bytes memory extra
    ) internal returns (bytes memory) {
        if (extra.length >= 68 && extra.toUint128(0) == PID) {
            Storage stg = Storage(extra.toAddress(16));
            bytes memory data = extra.slice(68, extra.length - 68);
            stg.write(extra.toUint256(36), data);
            extra = extra.slice(0, 68);
        }

        bytes memory raw = Integer.uint128ToFixedBytes(PID);
        raw = raw.concat(Integer.uint64ToFixedBytes(nonce));
        raw = raw.concat(Integer.uint128ToFixedBytes(asset));
        (bytes memory ab, uint16 al) = Integer.uint256ToVarBytes(amount);
        raw = raw.concat(Integer.uint16ToFixedBytes(al));
        raw = raw.concat(ab);
        raw = raw.concat(Integer.uint16ToFixedBytes(uint16(extra.length)));
        raw = raw.concat(extra);
        raw = raw.concat(Integer.uint64ToFixedBytes(uint64(block.timestamp)));
        raw = raw.concat(receiver);
        raw = raw.concat(new bytes(2));
        return raw;
    }

    // process || nonce || asset || amount || extra || timestamp || members || threshold || sig
    function mixin(bytes memory raw) public returns (bool) {
        require(!HALTED, "invalid state");
        require(raw.length >= 141, "event data too small");

        Event memory evt;
        uint256 offset = 0;

        uint128 id = raw.toUint128(offset);
        require(id == PID, "invalid process");
        offset = offset + 16;

        evt.nonce = raw.toUint64(offset);
        require(evt.nonce == INBOUND, "invalid nonce");
        INBOUND = INBOUND + 1;
        offset = offset + 8;

        (offset, id, evt.amount) = parseEventAsset(raw, offset);
        (offset, evt.extra, evt.timestamp) = parseEventExtra(raw, offset);
        (offset, evt.user) = parseEventUser(raw, offset);
        (evt.asset, evt.extra) = parseEventInput(id, evt.extra);

        offset = offset + 2;
        evt.sig = [raw.toUint256(offset), raw.toUint256(offset + 32)];
        uint256[2] memory message = raw
            .slice(0, offset - 2)
            .concat(new bytes(2))
            .hashToPoint();
        require(evt.sig.verifySingle(GROUP, message), "invalid signature");

        offset = offset + 64;
        require(raw.length == offset, "malformed event encoding");

        uint256 balance = balances[assets[evt.asset]];
        balances[assets[evt.asset]] = balance + evt.amount;

        emit MixinEvent(
            evt.nonce,
            evt.user,
            evt.asset,
            evt.amount,
            evt.extra,
            evt.timestamp
        );
        Asset(evt.asset).mint(evt.user, evt.amount);
        return User(evt.user).run(evt.asset, evt.amount, evt.extra);
    }

    function parseEventExtra(bytes memory raw, uint256 offset)
        internal
        pure
        returns (
            uint256,
            bytes memory,
            uint64
        )
    {
        uint256 size = raw.toUint16(offset);
        offset = offset + 2;
        bytes memory extra = raw.slice(offset, size);
        offset = offset + size;
        uint64 timestamp = raw.toUint64(offset);
        offset = offset + 8;
        return (offset, extra, timestamp);
    }

    function parseEventAsset(bytes memory raw, uint256 offset)
        internal
        pure
        returns (
            uint256,
            uint128,
            uint256
        )
    {
        uint128 id = raw.toUint128(offset);
        require(id > 0, "invalid asset");
        offset = offset + 16;
        uint256 size = raw.toUint16(offset);
        offset = offset + 2;
        require(size <= 32, "integer out of bounds");
        uint256 amount = new bytes(32 - size)
            .concat(raw.slice(offset, size))
            .toUint256(0);
        offset = offset + size;
        return (offset, id, amount);
    }

    function parseEventUser(bytes memory raw, uint256 offset)
        internal
        returns (uint256, address)
    {
        uint16 size = raw.toUint16(offset);
        size = 2 + size * 16 + 2;
        bytes memory members = raw.slice(offset, size);
        offset = offset + size;
        address user = getOrCreateUserContract(members);
        return (offset, user);
    }

    function parseEventInput(uint128 id, bytes memory extra)
        internal
        returns (address, bytes memory)
    {
        uint256 offset = 0;
        uint16 size = extra.toUint16(offset);
        offset = offset + 2;
        string memory symbol = string(extra.slice(offset, size));
        offset = offset + size;
        size = extra.toUint16(offset);
        offset = offset + 2;
        string memory name = string(extra.slice(offset, size));
        offset = offset + size;
        bytes memory input = extra.slice(offset, extra.length - offset);
        if (input.length == 68 && input.toUint128(0) == PID) {
            input = Storage(input.toAddress(16)).read(input.toUint256(36));
        }
        address asset = getOrCreateAssetContract(id, symbol, name);
        return (asset, input);
    }
}
        

contracts/User.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {Bytes} from "./libs/Bytes.sol";
import {IRegistry, Registrable} from "./Registrable.sol";
import {IERC20} from "./Asset.sol";

contract User is Registrable {
    using Bytes for bytes;

    event ProcessCalled(
        address indexed process,
        bytes input,
        bool result,
        bytes output
    );

    bytes public members;

    constructor(bytes memory _members) {
        members = _members;
    }

    function run(
        address asset,
        uint256 amount,
        bytes memory extra
    ) external onlyRegistry returns (bool) {
        if (extra.length < 28) {
            IRegistry(registry).claim(asset, amount);
            return true;
        }
        uint16 count = extra.toUint16(0);
        if (count < 1 || count > 16) {
            IRegistry(registry).claim(asset, amount);
            return true;
        }

        for (uint256 offset = 2; count >= 0 && offset < extra.length; count--) {
            bool primary = offset == 2;
            bytes memory data = extra.slice(offset, extra.length - offset);
            (uint256 size, bool success) = handle(data, asset, amount, primary);
            if (!success) {
                break;
            }
            offset = offset + size;
        }
        try IRegistry(registry).claim(asset, amount) {} catch {}
        return true;
    }

    function handle(
        bytes memory extra,
        address asset,
        uint256 amount,
        bool primary
    ) internal returns (uint256, bool) {
        uint256 offset = 0;
        if (offset + 20 > extra.length) {
            return (offset, false);
        }
        address process = extra.toAddress(offset);
        offset = offset + 20;
        if (primary) {
            IERC20(asset).approve(process, 0);
            IERC20(asset).approve(process, amount);
        }

        if (offset + 2 > extra.length) {
            return (offset, false);
        }
        uint256 size = extra.toUint16(offset);
        offset = offset + 2;

        if (offset + size > extra.length) {
            return (offset, false);
        }
        bytes memory input = extra.slice(offset, size);
        (bool result, bytes memory output) = process.call(input);
        offset = offset + size;

        emit ProcessCalled(process, input, result, output);
        return (offset, result);
    }
}
          

contracts/Asset.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {IRegistry, Registrable} from "./Registrable.sol";

interface IERC20 {
    function balanceOf(address who) external view returns (uint256);

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

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

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

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

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

abstract contract StandardToken is IERC20 {
    mapping(address => uint256) balances;
    mapping(address => mapping(address => uint256)) allowed;

    function balanceOf(address _owner)
        public
        view
        override
        returns (uint256 balance)
    {
        return balances[_owner];
    }

    function _transfer(
        address _from,
        address _to,
        uint256 _value
    ) internal {
        balances[_from] = balances[_from] - _value;
        balances[_to] = balances[_to] + _value;
        emit Transfer(_from, _to, _value);
    }

    function _transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) internal {
        uint256 _allowance = allowed[_from][msg.sender];
        allowed[_from][msg.sender] = _allowance - _value;
        _transfer(_from, _to, _value);
    }

    function approve(address _spender, uint256 _value)
        public
        override
        returns (bool)
    {
        // To change the approve amount you first have to reduce the addresses`
        //  allowance to zero by calling `approve(_spender, 0)` if it is not
        //  already 0 to mitigate the race condition described here:
        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
        require(
            (_value == 0) || (allowed[msg.sender][_spender] == 0),
            "approve on a non-zero allowance"
        );
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender)
        public
        view
        override
        returns (uint256 remaining)
    {
        return allowed[_owner][_spender];
    }
}

contract Asset is Registrable, StandardToken {
    uint128 public immutable id;

    string public name;
    string public symbol;
    uint256 public totalSupply;
    uint8 public constant decimals = 8;

    constructor(
        uint128 _id,
        string memory _name,
        string memory _symbol
    ) {
        id = _id;
        name = _name;
        symbol = _symbol;
    }

    function transferWithExtra(
        address to,
        uint256 value,
        bytes memory extra
    ) public returns (bool) {
        _transfer(msg.sender, to, value);
        IRegistry(registry).burn(to, value, extra);
        return true;
    }

    function transfer(address to, uint256 value)
        public
        override
        returns (bool)
    {
        return transferWithExtra(to, value, new bytes(0));
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) public override returns (bool) {
        _transferFrom(from, to, value);
        IRegistry(registry).burn(to, value, new bytes(0));
        return true;
    }

    function mint(address to, uint256 value) external onlyRegistry {
        balances[to] = balances[to] + value;
        totalSupply = totalSupply + value;
        emit Transfer(registry, to, value);
    }

    function burn(address to, uint256 value) external onlyRegistry {
        balances[to] = balances[to] - value;
        totalSupply = totalSupply - value;
        emit Transfer(to, registry, value);
    }
}
          

contracts/Factory.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {Asset} from "./Asset.sol";
import {User} from "./User.sol";

abstract contract Factory {
    uint256 public constant VERSION = 1;

    event UserCreated(address indexed at, bytes members);
    event AssetCreated(address indexed at, uint256 id);

    mapping(address => bytes) public users;
    mapping(address => uint128) public assets;
    mapping(uint256 => address) public contracts;

    function getOrCreateAssetContract(
        uint128 id,
        string memory symbol,
        string memory name
    ) internal returns (address) {
        address old = contracts[id];
        if (old != address(0)) {
            return old;
        }
        bytes memory code = getAssetContractCode(id, symbol, name);
        address asset = getContractAddress(code);
        if (assets[asset] > 0) {
            return asset;
        }
        address addr = deploy(code, VERSION);
        require(addr == asset, "malformed asset contract address");
        assets[asset] = id;
        contracts[id] = asset;
        emit AssetCreated(asset, id);
        return asset;
    }

    function getOrCreateUserContract(bytes memory members)
        internal
        returns (address)
    {
        uint256 id = uint256(keccak256(members));
        address old = contracts[id];
        if (old != address(0)) {
            return old;
        }
        bytes memory code = getUserContractCode(members);
        address user = getContractAddress(code);
        if (users[user].length > 0) {
            return user;
        }
        address addr = deploy(code, VERSION);
        require(addr == user, "malformed user contract address");
        users[user] = members;
        contracts[id] = user;
        emit UserCreated(user, members);
        return user;
    }

    function getUserContractCode(bytes memory members)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory code = type(User).creationCode;
        bytes memory args = abi.encode(members);
        return abi.encodePacked(code, args);
    }

    function getAssetContractCode(
        uint256 id,
        string memory symbol,
        string memory name
    ) internal pure returns (bytes memory) {
        bytes memory code = type(Asset).creationCode;
        bytes memory args = abi.encode(id, name, symbol);
        return abi.encodePacked(code, args);
    }

    function getContractAddress(bytes memory code)
        internal
        view
        returns (address)
    {
        code = abi.encodePacked(
            bytes1(0xff),
            address(this),
            VERSION,
            keccak256(code)
        );
        return address(uint160(uint256(keccak256(code))));
    }

    function deploy(bytes memory bytecode, uint256 _salt)
        internal
        returns (address)
    {
        address addr;
        assembly {
            addr := create2(
                callvalue(),
                add(bytecode, 0x20),
                mload(bytecode),
                _salt
            )

            if iszero(extcodesize(addr)) {
                revert(0, 0)
            }
        }
        return addr;
    }
}
          

contracts/Registrable.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

interface IRegistry {
    function claim(address asset, uint256 amount) external returns (bool);

    function burn(address user, uint256 amount, bytes memory extra) external returns (bool);
}

abstract contract Registrable {
    address public registry;

    modifier onlyRegistry() {
        require(msg.sender == registry, "not registry");
        _;
    }

    constructor() {
        registry = msg.sender;
    }
}
          

contracts/Storage.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

contract Storage {
    mapping(uint256 => bytes) internal values;

    function read(uint256 _key) public view returns (bytes memory) {
        return values[_key];
    }

    function write(uint256 _key, bytes memory raw) public {
        uint256 key = uint256(keccak256(raw));
        require(key == _key, "invalid key or raw");
        values[_key] = raw;
    }
}
          

contracts/libs/BLS.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

library BLS {
    // Field order
    uint256 constant N =
        21888242871839275222246405745257275088696311157297823662689037894645226208583;

    // Negated genarator of G2
    uint256 constant nG2x1 =
        11559732032986387107991004021392285783925812861821192530917403151452391805634;
    uint256 constant nG2x0 =
        10857046999023057135944570762232829481370756359578518086990519993285655852781;
    uint256 constant nG2y1 =
        17805874995975841540914202342111839520379459829704422454583296818431106115052;
    uint256 constant nG2y0 =
        13392588948715843804641432497768002650278120570034223513918757245338268106653;

    function verifySingle(
        uint256[2] memory signature,
        uint256[4] memory pubkey,
        uint256[2] memory message
    ) internal view returns (bool) {
        uint256[12] memory input = [
            signature[0],
            signature[1],
            nG2x1,
            nG2x0,
            nG2y1,
            nG2y0,
            message[0],
            message[1],
            pubkey[1],
            pubkey[0],
            pubkey[3],
            pubkey[2]
        ];
        uint256[1] memory out;
        bool success;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            success := staticcall(sub(gas(), 2000), 8, input, 384, out, 0x20)
            // use invalid() to make gas estimation work
            switch success
            case 0 {
                invalid()
            }
        }
        require(success, "BLS: paring check call failed");
        return out[0] != 0;
    }

    function hashToPoint(bytes memory data)
        internal
        view
        returns (uint256[2] memory p)
    {
        return mapToPoint(keccak256(data));
    }

    function mapToPoint(bytes32 _x)
        internal
        view
        returns (uint256[2] memory p)
    {
        uint256 x = uint256(_x) % N;
        uint256 y;
        bool found = false;
        while (true) {
            y = mulmod(x, x, N);
            y = mulmod(y, x, N);
            y = addmod(y, 3, N);
            (y, found) = sqrt(y);
            if (found) {
                p[0] = x;
                p[1] = y;
                break;
            }
            x = addmod(x, 1, N);
        }
    }

    function sqrt(uint256 xx) internal view returns (uint256 x, bool hasRoot) {
        bool success;
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            let freemem := mload(0x40)
            mstore(freemem, 0x20)
            mstore(add(freemem, 0x20), 0x20)
            mstore(add(freemem, 0x40), 0x20)
            mstore(add(freemem, 0x60), xx)
            // (N + 1) / 4 = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52
            mstore(
                add(freemem, 0x80),
                0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52
            )
            // N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
            mstore(
                add(freemem, 0xA0),
                0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
            )
            success := staticcall(
                sub(gas(), 2000),
                5,
                freemem,
                0xC0,
                freemem,
                0x20
            )
            switch success
            case 0 {
                invalid()
            }
            x := mload(freemem)
            hasRoot := eq(xx, mulmod(x, x, N))
        }
        require(success, "BLS: sqrt modexp call failed");
    }
}
          

contracts/libs/Bytes.sol

// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <goncalo.sa@consensys.net>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;

library Bytes {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}
          

contracts/libs/Integer.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.0 <0.9.0;

import {Bytes} from "./Bytes.sol";

library Integer {
    using Bytes for bytes;

    function uint16ToFixedBytes(uint16 x) internal pure returns (bytes memory) {
        bytes memory c = new bytes(2);
        bytes2 b = bytes2(x);
        for (uint256 i = 0; i < 2; i++) {
            c[i] = b[i];
        }
        return c;
    }

    function uint64ToFixedBytes(uint64 x) internal pure returns (bytes memory) {
        bytes memory c = new bytes(8);
        bytes8 b = bytes8(x);
        for (uint256 i = 0; i < 8; i++) {
            c[i] = b[i];
        }
        return c;
    }

    function uint128ToFixedBytes(uint128 x)
        internal
        pure
        returns (bytes memory)
    {
        bytes memory c = new bytes(16);
        bytes16 b = bytes16(x);
        for (uint256 i = 0; i < 16; i++) {
            c[i] = b[i];
        }
        return c;
    }

    function uint256ToVarBytes(uint256 x)
        internal
        pure
        returns (bytes memory, uint16)
    {
        bytes memory c = new bytes(32);
        bytes32 b = bytes32(x);
        uint16 offset = 0;
        for (uint16 i = 0; i < 32; i++) {
            c[i] = b[i];
            if (c[i] > 0 && offset == 0) {
                offset = i;
            }
        }
        uint16 size = 32 - offset;
        return (c.slice(offset, 32 - offset), size);
    }
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"bytes","name":"raw","internalType":"bytes"},{"type":"uint128","name":"pid","internalType":"uint128"}]},{"type":"event","name":"AssetCreated","inputs":[{"type":"address","name":"at","internalType":"address","indexed":true},{"type":"uint256","name":"id","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Halted","inputs":[{"type":"bool","name":"state","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Iterated","inputs":[{"type":"uint256[4]","name":"from","internalType":"uint256[4]","indexed":false},{"type":"uint256[4]","name":"to","internalType":"uint256[4]","indexed":false}],"anonymous":false},{"type":"event","name":"MixinEvent","inputs":[{"type":"uint64","name":"nonce","internalType":"uint64","indexed":true},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"address","name":"asset","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"bytes","name":"extra","internalType":"bytes","indexed":false},{"type":"uint64","name":"timestamp","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"MixinTransaction","inputs":[{"type":"bytes","name":"raw","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"UserCreated","inputs":[{"type":"address","name":"at","internalType":"address","indexed":true},{"type":"bytes","name":"members","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"GROUP","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"HALTED","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"INBOUND","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"OUTBOUND","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"PID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"VERSION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"assets","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balances","inputs":[{"type":"uint128","name":"","internalType":"uint128"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"burn","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"extra","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"claim","inputs":[{"type":"address","name":"asset","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"contracts","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"halt","inputs":[{"type":"bytes","name":"raw","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"iterate","inputs":[{"type":"bytes","name":"raw","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"mixin","inputs":[{"type":"bytes","name":"raw","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"users","inputs":[{"type":"address","name":"","internalType":"address"}]}]
              

Contract Creation Code

0x60a0604052600780546001600160881b03191690553480156200002157600080fd5b5060405162004d1a38038062004d1a833981016040819052620000449162000210565b81516080146200005357600080fd5b6000816001600160801b0316116200006a57600080fd5b6040518060800160405280620000906000856200011660201b62000f801790919060201c565b8152602001620000b06020856200011660201b62000f801790919060201c565b8152602001620000d06040856200011660201b62000f801790919060201c565b8152602001620000f06060856200011660201b62000f801790919060201c565b90526200010290600390600462000183565b506001600160801b03166080525062000328565b60006200012582602062000301565b835110156200017a5760405162461bcd60e51b815260206004820152601560248201527f746f55696e743235365f6f75744f66426f756e64730000000000000000000000604482015260640160405180910390fd5b50016020015190565b8260048101928215620001b4579160200282015b82811115620001b457825182559160200191906001019062000197565b50620001c2929150620001c6565b5090565b5b80821115620001c25760008155600101620001c7565b634e487b7160e01b600052604160045260246000fd5b80516001600160801b03811681146200020b57600080fd5b919050565b600080604083850312156200022457600080fd5b82516001600160401b03808211156200023c57600080fd5b818501915085601f8301126200025157600080fd5b815181811115620002665762000266620001dd565b604051601f8201601f19908116603f01168101908382118183101715620002915762000291620001dd565b81604052828152602093508884848701011115620002ae57600080fd5b600091505b82821015620002d25784820184015181830185015290830190620002b3565b82821115620002e45760008484830101525b9550620002f6915050858201620001f3565b925050509250929050565b600082198211156200032357634e487b7160e01b600052601160045260246000fd5b500190565b6080516149ba62000360600039600081816101d0015281816104c90152818161158301528181611b220152611c2201526149ba6000f3fe60806040523480156200001157600080fd5b5060043610620001095760003560e01c80638583592311620000a3578063aad3ec96116200006e578063aad3ec9614620002bc578063bab5462614620002d3578063f11b818814620002ea578063ffa1ad74146200031657600080fd5b80638583592314620002465780638d46b0c9146200025a578063944e7cb1146200027d578063a87430ba146200029657600080fd5b80635cae800511620000e45780635cae800514620001b35780635eaec0e414620001ca578063678d7732146200020b57806381ebf1c3146200022057600080fd5b806344d17187146200010e578063474da79a146200013a57806348093204146200017f575b600080fd5b620001256200011f366004620028cd565b6200031f565b60405190151581526020015b60405180910390f35b620001666200014b36600462002929565b6002602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200162000131565b6007546200019a90600160401b90046001600160401b031681565b6040516001600160401b03909116815260200162000131565b62000125620001c436600462002943565b62000412565b620001f27f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160801b03909116815260200162000131565b6007546200012590600160801b900460ff1681565b620002376200023136600462002929565b620009cd565b60405190815260200162000131565b6007546200019a906001600160401b031681565b620002376200026b36600462002983565b60086020526000908152604090205481565b620002946200028e36600462002943565b620009e5565b005b620002ad620002a7366004620029ae565b62000b4a565b60405162000131919062002a2d565b62000125620002cd36600462002a42565b62000bec565b62000294620002e436600462002943565b62000d17565b620001f2620002fb366004620029ae565b6001602052600090815260409020546001600160801b031681565b62000237600181565b336000908152600160205260408120546001600160801b0316620003605760405162461bcd60e51b8152600401620003579062002a6f565b60405180910390fd5b6001600160a01b03841660009081526020819052604090208054620003859062002a96565b1515905062000397575060016200040b565b604051632770a7eb60e21b81526001600160a01b0385166004820152602481018490523390639dc29fac90604401600060405180830381600087803b158015620003e057600080fd5b505af1158015620003f5573d6000803e3d6000fd5b50505050620004078433858562000fe2565b5060015b9392505050565b600754600090600160801b900460ff1615620004615760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420737461746560981b604482015260640162000357565b608d82511015620004ac5760405162461bcd60e51b8152602060048201526014602482015273195d995b9d0819185d18481d1bdbc81cdb585b1b60621b604482015260640162000357565b620004b66200266f565b600080620004c58582620011be565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160801b0316816001600160801b0316146200053c5760405162461bcd60e51b815260206004820152600f60248201526e696e76616c69642070726f6365737360881b604482015260640162000357565b6200054982601062002ae9565b915062000557858362001220565b6001600160401b0390811680855260075490911614620005aa5760405162461bcd60e51b815260206004820152600d60248201526c696e76616c6964206e6f6e636560981b604482015260640162000357565b600754620005c3906001600160401b0316600162002b04565b6007805467ffffffffffffffff19166001600160401b0392909216919091179055620005f182600862002ae9565b9150620005ff858362001281565b60608601529092509050620006158583620013d2565b6001600160401b031660a08601526080850152915062000636858362001442565b6001600160a01b03166020850152608084015190925062000659908290620014bd565b60808501526001600160a01b031660408401526200067982600262002ae9565b915060405180604001604052806200069b848862000f8090919063ffffffff16565b8152602001620006bb846020620006b3919062002ae9565b889062000f80565b905260c084015260408051600280825281830190925260009162000714916200070e9160208201818036833701905050620007076000620006fe60028962002b32565b8b919062001682565b906200179b565b6200181c565b60408051608081019182905291925062000759919060039060049082845b81548152602001906001019080831162000732575050505060c0870151919050836200183e565b620007785760405162461bcd60e51b8152600401620003579062002b4c565b6200078583604062002ae9565b925082865114620007d95760405162461bcd60e51b815260206004820152601860248201527f6d616c666f726d6564206576656e7420656e636f64696e670000000000000000604482015260640162000357565b6040808501516001600160a01b0316600090815260016020908152828220546001600160801b0316825260089052205460608501516200081a908262002ae9565b604080870180516001600160a01b03908116600090815260016020908152848220546001600160801b03168252600881529084902094909455905192880151885160608a015160808b015160a08c015195519685169693909416946001600160401b03909216937f4a2273975188c4aa53ba12e0e4de779bc15c4ecd111f951fbb454704a6eae88893620008af939062002b77565b60405180910390a46040808601516020870151606088015192516340c10f1960e01b81526001600160a01b039182166004820152602481019390935216906340c10f1990604401600060405180830381600087803b1580156200091157600080fd5b505af115801562000926573d6000803e3d6000fd5b5050506020860151604080880151606089015160808a01519251630f9d740360e31b81526001600160a01b039094169450637ceba018936200096c939060040162002bab565b602060405180830381600087803b1580156200098757600080fd5b505af11580156200099c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009c2919062002bdd565b979650505050505050565b60038160048110620009de57600080fd5b0154905081565b60075460009062000a269062000a04906001600160401b031662001a6e565b6040805180820190915260048152631210531560e21b6020820152906200179b565b90506000604051806040016040528062000a4b60008662000f8090919063ffffffff16565b815260200162000a6660208662000f8090919063ffffffff16565b90529050600062000a77836200181c565b60408051608081019182905291925062000ac0919060039060049082845b81548152602001906001019080831162000a9557505050505082846200183e9092919063ffffffff16565b62000adf5760405162461bcd60e51b8152600401620003579062002b4c565b6007805460ff600160801b808304821615810260ff60801b1990931692909217928390556040517f92333b0b676476985757350034668cb9ee247674ac7a7479de10cd761381f7339362000b3c9390049091161515815260200190565b60405180910390a150505050565b6000602081905290815260409020805462000b659062002a96565b80601f016020809104026020016040519081016040528092919081815260200182805462000b939062002a96565b801562000be45780601f1062000bb85761010080835404028352916020019162000be4565b820191906000526020600020905b81548152906001019060200180831162000bc657829003601f168201915b505050505081565b336000908152602081905260408120805482919062000c0b9062002a96565b90501162000c4b5760405162461bcd60e51b815260206004820152600c60248201526b34b73b30b634b2103ab9b2b960a11b604482015260640162000357565b6001600160a01b0383166000908152600160205260409020546001600160801b031662000c8c5760405162461bcd60e51b8152600401620003579062002a6f565b604051632770a7eb60e21b8152336004820152602481018390526001600160a01b03841690639dc29fac90604401600060405180830381600087803b15801562000cd557600080fd5b505af115801562000cea573d6000803e3d6000fd5b505060408051600081526020810190915262000d0e92503391508590859062000fe2565b50600192915050565b600754600160801b900460ff1662000d625760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420737461746560981b604482015260640162000357565b80516101001462000dab5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420696e7075742073697a6560701b604482015260640162000357565b6000604051806080016040528062000dce60008562000f8090919063ffffffff16565b815260200162000de960208562000f8090919063ffffffff16565b815260200162000dfb84604062000f80565b815260200162000e0d84606062000f80565b81525090506000604051806040016040528062000e3560808662000f8090919063ffffffff16565b815260200162000e478560a062000f80565b81525090506000604051806040016040528062000e6f60c08762000f8090919063ffffffff16565b815260200162000e818660e062000f80565b90529050600062000e996200070e8683608062001682565b60408051608081019182905291925062000ee2919060039060049082845b81548152602001906001019080831162000eb757505050505082856200183e9092919063ffffffff16565b62000f015760405162461bcd60e51b8152600401620003579062002b4c565b62000f0e8285836200183e565b62000f2d5760405162461bcd60e51b8152600401620003579062002b4c565b7f20b54a4e4d72fb59d7f4da768f89618921cb2abc9d2ede08c065bb1f36c745f560038560405162000f6192919062002c01565b60405180910390a162000f786003856004620026b3565b505050505050565b600062000f8f82602062002ae9565b8351101562000fd95760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b604482015260640162000357565b50016020015190565b6001600160a01b038381166000908152600160209081526040808320546001600160801b031683526008825280832054600754948916845291839052822080549193620010f692600160401b9091046001600160401b03169190620010479062002a96565b80601f0160208091040260200160405190810160405280929190818152602001828054620010759062002a96565b8015620010c65780601f106200109a57610100808354040283529160200191620010c6565b820191906000526020600020905b815481529060010190602001808311620010a857829003601f168201915b505050506001600160a01b0389166000908152600160205260409020546001600160801b03169050878762001b08565b90507fdb53e751d28ed0d6e3682814bf8d23f7dd7b29c94f74a56fbb7f88e9dca9f39b8160405162001129919062002a2d565b60405180910390a16200113d848362002b32565b6001600160a01b0386166000908152600160208181526040808420546001600160801b031684526008909152909120919091556007546200119091600160401b9091046001600160401b03169062002b04565b600760086101000a8154816001600160401b0302191690836001600160401b03160217905550505050505050565b6000620011cd82601062002ae9565b83511015620012175760405162461bcd60e51b8152602060048201526015602482015274746f55696e743132385f6f75744f66426f756e647360581b604482015260640162000357565b50016010015190565b60006200122f82600862002ae9565b83511015620012785760405162461bcd60e51b8152602060048201526014602482015273746f55696e7436345f6f75744f66426f756e647360601b604482015260640162000357565b50016008015190565b6000808080620012928686620011be565b90506000816001600160801b031611620012c05760405162461bcd60e51b8152600401620003579062002a6f565b620012cd85601062002ae9565b94506000620012dd878762001d23565b61ffff169050620012f086600262002ae9565b955060208111156200133d5760405162461bcd60e51b8152602060048201526015602482015274696e7465676572206f7574206f6620626f756e647360581b604482015260640162000357565b6000620013b681620013af620013558b8b8762001682565b6200136286602062002b32565b6001600160401b038111156200137c576200137c620027fe565b6040519080825280601f01601f191660200182016040528015620013a7576020820181803683370190505b50906200179b565b9062000f80565b9050620013c4828862002ae9565b989297509550909350505050565b600060608180620013e4868662001d23565b61ffff169050620013f785600262002ae9565b945060006200140887878462001682565b905062001416828762002ae9565b9550600062001426888862001220565b90506200143587600862002ae9565b9891975095509350505050565b6000808062001452858562001d23565b90506200146181601062002c62565b6200146e90600262002c8f565b6200147b90600262002c8f565b9050600062001490868661ffff851662001682565b9050620014a261ffff83168662002ae9565b94506000620014b18262001d84565b95979596505050505050565b600060608180620014cf858262001d23565b9050620014de82600262002ae9565b91506000620014f3868461ffff851662001682565b90506200150561ffff83168462002ae9565b925062001513868462001d23565b91506200152283600262002ae9565b9250600062001537878561ffff861662001682565b90506200154961ffff84168562002ae9565b935060006200156a85868a5162001561919062002b32565b8a919062001682565b905080516044148015620015bb57506001600160801b037f000000000000000000000000000000000000000000000000000000000000000016620015b0826000620011be565b6001600160801b0316145b156200166357620015ce81601062001f1a565b6001600160a01b031663ed2e5a97620015e983602462000f80565b6040518263ffffffff1660e01b81526004016200160891815260200190565b60006040518083038186803b1580156200162157600080fd5b505afa15801562001636573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001660919081019062002caf565b90505b6000620016728a858562001f83565b9a91995090975050505050505050565b6060816200169281601f62002ae9565b1015620016d35760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640162000357565b620016df828462002ae9565b84511015620017255760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640162000357565b60608215801562001746576040519150600082526020820160405262001792565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156200178157805183526020928301920162001767565b5050858452601f01601f1916604052505b50949350505050565b6060806040519050835180825260208201818101602087015b81831015620017ce578051835260209283019201620017b4565b50855184518101855292509050808201602086015b81831015620017fd578051835260209283019201620017e3565b508651929092011591909101601f01601f191660405250905092915050565b62001826620026f6565b6200183882805190602001206200211a565b92915050565b6000806040518061018001604052808660006002811062001863576200186362002d25565b602002015181526020018660016002811062001883576200188362002d25565b602002015181526020017f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c281526020017f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed81526020017f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec81526020017f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d8152602001846000600281106200193b576200193b62002d25565b60200201518152602001846001600281106200195b576200195b62002d25565b60200201518152602001856001600481106200197b576200197b62002d25565b60200201518152602001856000600481106200199b576200199b62002d25565b6020020151815260200185600360048110620019bb57620019bb62002d25565b6020020151815260200185600260048110620019db57620019db62002d25565b602002015190529050620019ee62002714565b60006020826101808560086107d05a03fa905080801562001a0f5762001a11565bfe5b508062001a615760405162461bcd60e51b815260206004820152601d60248201527f424c533a20706172696e6720636865636b2063616c6c206661696c6564000000604482015260640162000357565b5051151595945050505050565b6040805160088082528183019092526060916000919060208201818036833701905050905060c083901b60005b600881101562001aff5781816008811062001aba5762001aba62002d25565b1a60f81b83828151811062001ad35762001ad362002d25565b60200101906001600160f81b031916908160001a9053508062001af68162002d3b565b91505062001a9b565b50909392505050565b6060604482511015801562001b5a57506001600160801b037f00000000000000000000000000000000000000000000000000000000000000001662001b4f836000620011be565b6001600160801b0316145b1562001c1a57600062001b6f83601062001f1a565b9050600062001b91604480865162001b88919062002b32565b86919062001682565b90506001600160a01b038216637341a70e62001baf86602462000f80565b836040518363ffffffff1660e01b815260040162001bcf92919062002d59565b600060405180830381600087803b15801562001bea57600080fd5b505af115801562001bff573d6000803e3d6000fd5b5062001c15925086915060009050604462001682565b935050505b600062001c477f0000000000000000000000000000000000000000000000000000000000000000620021d2565b905062001c6062001c588862001a6e565b82906200179b565b905062001c7162001c5886620021d2565b905060008062001c818662002263565b9150915062001c9c62001c948262002386565b84906200179b565b925062001caa83836200179b565b925062001cbc62001c94865162002386565b925062001cca83866200179b565b925062001cdb62001c944262001a6e565b925062001ce983896200179b565b60408051600280825281830190925291945062001d1691906020820181803683370190505084906200179b565b9998505050505050505050565b600062001d3282600262002ae9565b8351101562001d7b5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640162000357565b50016002015190565b80516020808301919091206000818152600290925260408220546001600160a01b0316801562001db5579392505050565b600062001dc28562002417565b9050600062001dd18262002496565b6001600160a01b03811660009081526020819052604081208054929350909162001dfb9062002a96565b9050111562001e0d5795945050505050565b600062001e1c836001620024ee565b9050816001600160a01b0316816001600160a01b03161462001e815760405162461bcd60e51b815260206004820152601f60248201527f6d616c666f726d6564207573657220636f6e7472616374206164647265737300604482015260640162000357565b6001600160a01b038216600090815260208181526040909120885162001eaa928a019062002732565b506000858152600260205260409081902080546001600160a01b0319166001600160a01b03851690811790915590517f2451915984c9d5ac7f24f9ef5513c322d23de620a629e29e7a40f2bc117c80849062001f08908a9062002a2d565b60405180910390a25095945050505050565b600062001f2982601462002ae9565b8351101562001f735760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b604482015260640162000357565b500160200151600160601b900490565b6001600160801b0383166000908152600260205260408120546001600160a01b0316801562001fb45790506200040b565b600062001fcc866001600160801b0316868662002508565b9050600062001fdb8262002496565b6001600160a01b0381166000908152600160205260409020549091506001600160801b031615620020115792506200040b915050565b600062002020836001620024ee565b9050816001600160a01b0316816001600160a01b031614620020855760405162461bcd60e51b815260206004820181905260248201527f6d616c666f726d656420617373657420636f6e74726163742061646472657373604482015260640162000357565b6001600160a01b038216600081815260016020908152604080832080546fffffffffffffffffffffffffffffffff19166001600160801b038e16908117909155808452600283529281902080546001600160a01b03191685179055519182527f20df459a0f7f1bc64a42346a9e6536111a3512be01de7a0f5327a4e13b337038910160405180910390a2509695505050505050565b62002124620026f6565b600062002141600080516020620049668339815191528462002d74565b90506000805b6000805160206200496683398151915283840991506000805160206200496683398151915283830991506000805160206200496683398151915260038308915062002192826200258d565b90925090508015620021ae5782845260208401829052620021ca565b6000805160206200496683398151915260018408925062002147565b505050919050565b60408051601080825281830190925260609160009190602082018180368337019050509050608083901b60005b601081101562001aff578181601081106200221e576200221e62002d25565b1a60f81b83828151811062002237576200223762002d25565b60200101906001600160f81b031916908160001a905350806200225a8162002d3b565b915050620021ff565b6040805160208082528183019092526060916000918291602082018180368337019050509050836000805b60208161ffff1610156200234557828161ffff1660208110620022b557620022b562002d25565b1a60f81b848261ffff1681518110620022d257620022d262002d25565b60200101906001600160f81b031916908160001a905350600060f81b848261ffff168151811062002307576200230762002d25565b01602001516001600160f81b03191611801562002326575061ffff8216155b1562002330578091505b806200233c8162002d97565b9150506200228e565b5060006200235582602062002dbc565b90506200237a61ffff83166200236d84602062002dbc565b86919061ffff1662001682565b97909650945050505050565b6040805160028082528183019092526060916000919060208201818036833701905050905060f083901b60005b600281101562001aff57818160028110620023d257620023d262002d25565b1a60f81b838281518110620023eb57620023eb62002d25565b60200101906001600160f81b031916908160001a905350806200240e8162002d3b565b915050620023b3565b60606000604051806020016200242d90620027ae565b6020820181038252601f19601f82011660405250905060008360405160200162002458919062002a2d565b604051602081830303815290604052905081816040516020016200247e92919062002de2565b60405160208183030381529060405292505050919050565b8051602091820120604080516001600160f81b0319818501523060601b6bffffffffffffffffffffffff1916602182015260016035820152605580820193909352815180820390930183526075019052805191012090565b6000808284516020860134f59050803b6200040b57600080fd5b60606000604051806020016200251e90620027bc565b6020820181038252601f19601f82011660405250905060008584866040516020016200254d9392919062002e0c565b604051602081830303815290604052905081816040516020016200257392919062002de2565b604051602081830303815290604052925050509392505050565b600080600060405160208152602080820152602060408201528460608201527f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f5260808201526000805160206200496683398151915260a082015260208160c08360056107d05a03fa915081801562001a0f5750519250600080516020620049668339815191528380098414915080620026695760405162461bcd60e51b815260206004820152601c60248201527f424c533a2073717274206d6f646578702063616c6c206661696c656400000000604482015260640162000357565b50915091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a081019190915260c08101620026ae620026f6565b905290565b8260048101928215620026e4579160200282015b82811115620026e4578251825591602001919060010190620026c7565b50620026f2929150620027ca565b5090565b60405180604001604052806002906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b828054620027409062002a96565b90600052602060002090601f016020900481019282620027645760008555620026e4565b82601f106200277f57805160ff1916838001178555620026e4565b82800160010185558215620026e45791820182811115620026e4578251825591602001919060010190620026c7565b610d2d8062002e4683390190565b610df38062003b7383390190565b5b80821115620026f25760008155600101620027cb565b80356001600160a01b0381168114620027f957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200283f576200283f620027fe565b604052919050565b60006001600160401b03821115620028635762002863620027fe565b50601f01601f191660200190565b600082601f8301126200288357600080fd5b81356200289a620028948262002847565b62002814565b818152846020838601011115620028b057600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215620028e357600080fd5b620028ee84620027e1565b92506020840135915060408401356001600160401b038111156200291157600080fd5b6200291f8682870162002871565b9150509250925092565b6000602082840312156200293c57600080fd5b5035919050565b6000602082840312156200295657600080fd5b81356001600160401b038111156200296d57600080fd5b6200297b8482850162002871565b949350505050565b6000602082840312156200299657600080fd5b81356001600160801b03811681146200040b57600080fd5b600060208284031215620029c157600080fd5b6200040b82620027e1565b60005b83811015620029e9578181015183820152602001620029cf565b83811115620029f9576000848401525b50505050565b6000815180845262002a19816020860160208601620029cc565b601f01601f19169290920160200192915050565b6020815260006200040b6020830184620029ff565b6000806040838503121562002a5657600080fd5b62002a6183620027e1565b946020939093013593505050565b6020808252600d908201526c1a5b9d985b1a5908185cdcd95d609a1b604082015260600190565b600181811c9082168062002aab57607f821691505b6020821081141562002acd57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111562002aff5762002aff62002ad3565b500190565b60006001600160401b0380831681851680830382111562002b295762002b2962002ad3565b01949350505050565b60008282101562002b475762002b4762002ad3565b500390565b602080825260119082015270696e76616c6964207369676e617475726560781b604082015260600190565b83815260606020820152600062002b926060830185620029ff565b90506001600160401b0383166040830152949350505050565b60018060a01b038416815282602082015260606040820152600062002bd46060830184620029ff565b95945050505050565b60006020828403121562002bf057600080fd5b815180151581146200040b57600080fd5b6101008101818460005b600481101562002c2c57815483526020909201916001918201910162002c0b565b505050608082018360005b600481101562002c5857815183526020928301929091019060010162002c37565b5050509392505050565b600061ffff8083168185168183048111821515161562002c865762002c8662002ad3565b02949350505050565b600061ffff80831681851680830382111562002b295762002b2962002ad3565b60006020828403121562002cc257600080fd5b81516001600160401b0381111562002cd957600080fd5b8201601f8101841362002ceb57600080fd5b805162002cfc620028948262002847565b81815285602083850101111562002d1257600080fd5b62002bd4826020830160208601620029cc565b634e487b7160e01b600052603260045260246000fd5b600060001982141562002d525762002d5262002ad3565b5060010190565b8281526040602082015260006200297b6040830184620029ff565b60008262002d9257634e487b7160e01b600052601260045260246000fd5b500690565b600061ffff8083168181141562002db25762002db262002ad3565b6001019392505050565b600061ffff8381169083168181101562002dda5762002dda62002ad3565b039392505050565b6000835162002df6818460208801620029cc565b83519083019062002b29818360208801620029cc565b83815260606020820152600062002e276060830185620029ff565b828103604084015262002e3b8185620029ff565b969550505050505056fe60806040523480156200001157600080fd5b5060405162000d2d38038062000d2d83398101604081905262000034916200011f565b600080546001600160a01b0319163317905580516200005b90600190602084019062000063565b505062000238565b8280546200007190620001fb565b90600052602060002090601f016020900481019282620000955760008555620000e0565b82601f10620000b057805160ff1916838001178555620000e0565b82800160010185558215620000e0579182015b82811115620000e0578251825591602001919060010190620000c3565b50620000ee929150620000f2565b5090565b5b80821115620000ee5760008155600101620000f3565b634e487b7160e01b600052604160045260246000fd5b600060208083850312156200013357600080fd5b82516001600160401b03808211156200014b57600080fd5b818501915085601f8301126200016057600080fd5b81518181111562000175576200017562000109565b604051601f8201601f19908116603f01168101908382118183101715620001a057620001a062000109565b816040528281528886848701011115620001b957600080fd5b600093505b82841015620001dd5784840186015181850187015292850192620001be565b82841115620001ef5760008684830101525b98975050505050505050565b600181811c908216806200021057607f821691505b602082108114156200023257634e487b7160e01b600052602260045260246000fd5b50919050565b610ae580620002486000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637b103999146100465780637ceba01814610076578063bdd4d18d14610099575b600080fd5b600054610059906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b610089610084366004610855565b6100ae565b604051901515815260200161006d565b6100a161035e565b60405161006d919061098a565b600080546001600160a01b031633146100fd5760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064015b60405180910390fd5b601c8251101561019757600054604051635569f64b60e11b81526001600160a01b038681166004830152602482018690529091169063aad3ec9690604401602060405180830381600087803b15801561015557600080fd5b505af1158015610169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061018d919061099d565b5060019050610357565b60006101a383826103ec565b905060018161ffff1610806101bc575060108161ffff16115b1561025257600054604051635569f64b60e11b81526001600160a01b038781166004830152602482018790529091169063aad3ec9690604401602060405180830381600087803b15801561020f57600080fd5b505af1158015610223573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610247919061099d565b506001915050610357565b60025b83518110156102c757600081600214905060006102818384885161027991906109d5565b889190610449565b9050600080610292838b8b87610556565b91509150806102a457505050506102c7565b6102ae82866109ec565b94505050505081806102bf90610a04565b925050610255565b50600054604051635569f64b60e11b81526001600160a01b038781166004830152602482018790529091169063aad3ec9690604401602060405180830381600087803b15801561031657600080fd5b505af1925050508015610346575060408051601f3d908101601f191682019092526103439181019061099d565b60015b61034f57610351565b505b60019150505b9392505050565b6001805461036b90610a22565b80601f016020809104026020016040519081016040528092919081815260200182805461039790610a22565b80156103e45780601f106103b9576101008083540402835291602001916103e4565b820191906000526020600020905b8154815290600101906020018083116103c757829003601f168201915b505050505081565b60006103f98260026109ec565b835110156104405760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b60448201526064016100f4565b50016002015190565b60608161045781601f6109ec565b10156104965760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016100f4565b6104a082846109ec565b845110156104e45760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016100f4565b606082158015610503576040519150600082526020820160405261054d565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561053c578051835260209283019201610524565b5050858452601f01601f1916604052505b50949350505050565b6000806000865181601461056a91906109ec565b111561057b579150600090506107d1565b600061058788836107da565b90506105948260146109ec565b915084156106a35760405163095ea7b360e01b81526001600160a01b0382811660048301526000602483015288169063095ea7b390604401602060405180830381600087803b1580156105e657600080fd5b505af11580156105fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061e919061099d565b5060405163095ea7b360e01b81526001600160a01b0382811660048301526024820188905288169063095ea7b390604401602060405180830381600087803b15801561066957600080fd5b505af115801561067d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a1919061099d565b505b87516106b08360026109ec565b11156106c257509150600090506107d1565b60006106ce89846103ec565b61ffff1690506106df8360026109ec565b89519093506106ee82856109ec565b111561070357826000945094505050506107d1565b60006107108a8584610449565b9050600080846001600160a01b03168360405161072d9190610a5d565b6000604051808303816000865af19150503d806000811461076a576040519150601f19603f3d011682016040523d82523d6000602084013e61076f565b606091505b50909250905061077f84876109ec565b9550846001600160a01b03167f374b40ceb7994eb007a897f9cafaa351e1e66f4dba809f52995372acc1f12d308484846040516107be93929190610a79565b60405180910390a2509395509293505050505b94509492505050565b60006107e78260146109ec565b8351101561082f5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b60448201526064016100f4565b500160200151600160601b900490565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561086a57600080fd5b83356001600160a01b038116811461088157600080fd5b925060208401359150604084013567ffffffffffffffff808211156108a557600080fd5b818601915086601f8301126108b957600080fd5b8135818111156108cb576108cb61083f565b604051601f8201601f19908116603f011681019083821181831017156108f3576108f361083f565b8160405282815289602084870101111561090c57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60005b83811015610949578181015183820152602001610931565b83811115610958576000848401525b50505050565b6000815180845261097681602086016020860161092e565b601f01601f19169290920160200192915050565b602081526000610357602083018461095e565b6000602082840312156109af57600080fd5b8151801515811461035757600080fd5b634e487b7160e01b600052601160045260246000fd5b6000828210156109e7576109e76109bf565b500390565b600082198211156109ff576109ff6109bf565b500190565b600061ffff821680610a1857610a186109bf565b6000190192915050565b600181811c90821680610a3657607f821691505b60208210811415610a5757634e487b7160e01b600052602260045260246000fd5b50919050565b60008251610a6f81846020870161092e565b9190910192915050565b606081526000610a8c606083018661095e565b84151560208401528281036040840152610aa6818561095e565b969550505050505056fea265627a7a7231582092fbf7a05fe947ca227e879053d3cd676116b315b5dc2c6169168c1a6fea99f664736f6c6343000809003260a06040523480156200001157600080fd5b5060405162000df338038062000df38339810160408190526200003491620001fb565b600080546001600160a01b031916331790556001600160801b03831660805281516200006890600390602085019062000088565b5080516200007e90600490602084019062000088565b50505050620002c2565b828054620000969062000285565b90600052602060002090601f016020900481019282620000ba576000855562000105565b82601f10620000d557805160ff191683800117855562000105565b8280016001018555821562000105579182015b8281111562000105578251825591602001919060010190620000e8565b506200011392915062000117565b5090565b5b8082111562000113576000815560010162000118565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015657600080fd5b81516001600160401b03808211156200017357620001736200012e565b604051601f8301601f19908116603f011681019082821181831017156200019e576200019e6200012e565b81604052838152602092508683858801011115620001bb57600080fd5b600091505b83821015620001df5785820183015181830184015290820190620001c0565b83821115620001f15760008385830101525b9695505050505050565b6000806000606084860312156200021157600080fd5b83516001600160801b03811681146200022957600080fd5b60208501519093506001600160401b03808211156200024757600080fd5b620002558783880162000144565b935060408601519150808211156200026c57600080fd5b506200027b8682870162000144565b9150509250925092565b600181811c908216806200029a57607f821691505b60208210811415620002bc57634e487b7160e01b600052602260045260246000fd5b50919050565b608051610b15620002de60003960006102230152610b156000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c5780639dc29fac116100665780639dc29fac146101f8578063a9059cbb1461020b578063af640d0f1461021e578063dd62ed3e1461026657600080fd5b806370a082311461019c5780637b103999146101c557806395d89b41146101f057600080fd5b80631f6847fe116100c85780631f6847fe1461014757806323b872dd1461015a578063313ce5671461016d57806340c10f191461018757600080fd5b806306fdde03146100ef578063095ea7b31461010d57806318160ddd14610130575b600080fd5b6100f761029f565b604051610104919061084a565b60405180910390f35b61012061011b366004610879565b61032d565b6040519015158152602001610104565b61013960055481565b604051908152602001610104565b6101206101553660046108b9565b610412565b610120610168366004610984565b6104b0565b610175600881565b60405160ff9091168152602001610104565b61019a610195366004610879565b6104fb565b005b6101396101aa3660046109c0565b6001600160a01b031660009081526001602052604090205490565b6000546101d8906001600160a01b031681565b6040516001600160a01b039091168152602001610104565b6100f76105db565b61019a610206366004610879565b6105e8565b610120610219366004610879565b6106c1565b6102457f000000000000000000000000000000000000000000000000000000000000000081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610104565b6101396102743660046109db565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b600380546102ac90610a0e565b80601f01602080910402602001604051908101604052809291908181526020018280546102d890610a0e565b80156103255780601f106102fa57610100808354040283529160200191610325565b820191906000526020600020905b81548152906001019060200180831161030857829003601f168201915b505050505081565b600081158061035d57503360009081526002602090815260408083206001600160a01b0387168452909152902054155b6103ae5760405162461bcd60e51b815260206004820152601f60248201527f617070726f7665206f6e2061206e6f6e2d7a65726f20616c6c6f77616e63650060448201526064015b60405180910390fd5b3360008181526002602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b600061041f3385856106e5565b6000546040516344d1718760e01b81526001600160a01b03909116906344d171879061045390879087908790600401610a49565b602060405180830381600087803b15801561046d57600080fd5b505af1158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190610a79565b506001949350505050565b60006104bd84848461079a565b600080546040805192835260208301908190526344d1718760e01b90526001600160a01b0316906344d1718790610453908690869060248101610a49565b6000546001600160a01b031633146105445760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610568908290610ab1565b6001600160a01b03831660009081526001602052604090205560055461058f908290610ab1565b6005556000546040518281526001600160a01b038481169216907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b600480546102ac90610a0e565b6000546001600160a01b031633146106315760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610655908290610ac9565b6001600160a01b03831660009081526001602052604090205560055461067c908290610ac9565b6005556000546040518281526001600160a01b03918216918416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016105cf565b604080516000808252602082019092526106de9084908490610412565b9392505050565b6001600160a01b038316600090815260016020526040902054610709908290610ac9565b6001600160a01b038085166000908152600160205260408082209390935590841681522054610739908290610ab1565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061078d9085815260200190565b60405180910390a3505050565b6001600160a01b03831660009081526002602090815260408083203384529091529020546107c88282610ac9565b6001600160a01b03851660009081526002602090815260408083203384529091529020556107f78484846106e5565b50505050565b6000815180845260005b8181101561082357602081850181015186830182015201610807565b81811115610835576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006106de60208301846107fd565b80356001600160a01b038116811461087457600080fd5b919050565b6000806040838503121561088c57600080fd5b6108958361085d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156108ce57600080fd5b6108d78461085d565b925060208401359150604084013567ffffffffffffffff808211156108fb57600080fd5b818601915086601f83011261090f57600080fd5b813581811115610921576109216108a3565b604051601f8201601f19908116603f01168101908382118183101715610949576109496108a3565b8160405282815289602084870101111561096257600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060006060848603121561099957600080fd5b6109a28461085d565b92506109b06020850161085d565b9150604084013590509250925092565b6000602082840312156109d257600080fd5b6106de8261085d565b600080604083850312156109ee57600080fd5b6109f78361085d565b9150610a056020840161085d565b90509250929050565b600181811c90821680610a2257607f821691505b60208210811415610a4357634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b0384168152826020820152606060408201526000610a7060608301846107fd565b95945050505050565b600060208284031215610a8b57600080fd5b815180151581146106de57600080fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115610ac457610ac4610a9b565b500190565b600082821015610adb57610adb610a9b565b50039056fea265627a7a72315820e4d33a6aec92022b9335cb5ab741e8642db27bf8eedbdc8f2e4317e41206159964736f6c6343000809003230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47a265627a7a723158206a8dd884554f3e66fede647c63be615457016e4d43ad521e57f0e9934dcb034864736f6c63430008090032000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000bd67087276ce3263b9333aa337e212a400000000000000000000000000000000000000000000000000000000000000801b0b73f760f5a1fc2d3b14b18a1fb5f7d8e93366ac283423c7b6413dd869bf1300a4398f2222cca7c31cd56b4557249bf9f3c538b30b06e3a9a4c830a9b48feb25fc87924ed7906607d59b6e9555230e73b46378252923ac719a328c7235cb03030e7999862a645112eefee572b4f930a8c66b4141d0f8d76558364ed539c03e

Deployed ByteCode

0x60806040523480156200001157600080fd5b5060043610620001095760003560e01c80638583592311620000a3578063aad3ec96116200006e578063aad3ec9614620002bc578063bab5462614620002d3578063f11b818814620002ea578063ffa1ad74146200031657600080fd5b80638583592314620002465780638d46b0c9146200025a578063944e7cb1146200027d578063a87430ba146200029657600080fd5b80635cae800511620000e45780635cae800514620001b35780635eaec0e414620001ca578063678d7732146200020b57806381ebf1c3146200022057600080fd5b806344d17187146200010e578063474da79a146200013a57806348093204146200017f575b600080fd5b620001256200011f366004620028cd565b6200031f565b60405190151581526020015b60405180910390f35b620001666200014b36600462002929565b6002602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200162000131565b6007546200019a90600160401b90046001600160401b031681565b6040516001600160401b03909116815260200162000131565b62000125620001c436600462002943565b62000412565b620001f27f00000000000000000000000000000000bd67087276ce3263b9333aa337e212a481565b6040516001600160801b03909116815260200162000131565b6007546200012590600160801b900460ff1681565b620002376200023136600462002929565b620009cd565b60405190815260200162000131565b6007546200019a906001600160401b031681565b620002376200026b36600462002983565b60086020526000908152604090205481565b620002946200028e36600462002943565b620009e5565b005b620002ad620002a7366004620029ae565b62000b4a565b60405162000131919062002a2d565b62000125620002cd36600462002a42565b62000bec565b62000294620002e436600462002943565b62000d17565b620001f2620002fb366004620029ae565b6001602052600090815260409020546001600160801b031681565b62000237600181565b336000908152600160205260408120546001600160801b0316620003605760405162461bcd60e51b8152600401620003579062002a6f565b60405180910390fd5b6001600160a01b03841660009081526020819052604090208054620003859062002a96565b1515905062000397575060016200040b565b604051632770a7eb60e21b81526001600160a01b0385166004820152602481018490523390639dc29fac90604401600060405180830381600087803b158015620003e057600080fd5b505af1158015620003f5573d6000803e3d6000fd5b50505050620004078433858562000fe2565b5060015b9392505050565b600754600090600160801b900460ff1615620004615760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420737461746560981b604482015260640162000357565b608d82511015620004ac5760405162461bcd60e51b8152602060048201526014602482015273195d995b9d0819185d18481d1bdbc81cdb585b1b60621b604482015260640162000357565b620004b66200266f565b600080620004c58582620011be565b90507f00000000000000000000000000000000bd67087276ce3263b9333aa337e212a46001600160801b0316816001600160801b0316146200053c5760405162461bcd60e51b815260206004820152600f60248201526e696e76616c69642070726f6365737360881b604482015260640162000357565b6200054982601062002ae9565b915062000557858362001220565b6001600160401b0390811680855260075490911614620005aa5760405162461bcd60e51b815260206004820152600d60248201526c696e76616c6964206e6f6e636560981b604482015260640162000357565b600754620005c3906001600160401b0316600162002b04565b6007805467ffffffffffffffff19166001600160401b0392909216919091179055620005f182600862002ae9565b9150620005ff858362001281565b60608601529092509050620006158583620013d2565b6001600160401b031660a08601526080850152915062000636858362001442565b6001600160a01b03166020850152608084015190925062000659908290620014bd565b60808501526001600160a01b031660408401526200067982600262002ae9565b915060405180604001604052806200069b848862000f8090919063ffffffff16565b8152602001620006bb846020620006b3919062002ae9565b889062000f80565b905260c084015260408051600280825281830190925260009162000714916200070e9160208201818036833701905050620007076000620006fe60028962002b32565b8b919062001682565b906200179b565b6200181c565b60408051608081019182905291925062000759919060039060049082845b81548152602001906001019080831162000732575050505060c0870151919050836200183e565b620007785760405162461bcd60e51b8152600401620003579062002b4c565b6200078583604062002ae9565b925082865114620007d95760405162461bcd60e51b815260206004820152601860248201527f6d616c666f726d6564206576656e7420656e636f64696e670000000000000000604482015260640162000357565b6040808501516001600160a01b0316600090815260016020908152828220546001600160801b0316825260089052205460608501516200081a908262002ae9565b604080870180516001600160a01b03908116600090815260016020908152848220546001600160801b03168252600881529084902094909455905192880151885160608a015160808b015160a08c015195519685169693909416946001600160401b03909216937f4a2273975188c4aa53ba12e0e4de779bc15c4ecd111f951fbb454704a6eae88893620008af939062002b77565b60405180910390a46040808601516020870151606088015192516340c10f1960e01b81526001600160a01b039182166004820152602481019390935216906340c10f1990604401600060405180830381600087803b1580156200091157600080fd5b505af115801562000926573d6000803e3d6000fd5b5050506020860151604080880151606089015160808a01519251630f9d740360e31b81526001600160a01b039094169450637ceba018936200096c939060040162002bab565b602060405180830381600087803b1580156200098757600080fd5b505af11580156200099c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009c2919062002bdd565b979650505050505050565b60038160048110620009de57600080fd5b0154905081565b60075460009062000a269062000a04906001600160401b031662001a6e565b6040805180820190915260048152631210531560e21b6020820152906200179b565b90506000604051806040016040528062000a4b60008662000f8090919063ffffffff16565b815260200162000a6660208662000f8090919063ffffffff16565b90529050600062000a77836200181c565b60408051608081019182905291925062000ac0919060039060049082845b81548152602001906001019080831162000a9557505050505082846200183e9092919063ffffffff16565b62000adf5760405162461bcd60e51b8152600401620003579062002b4c565b6007805460ff600160801b808304821615810260ff60801b1990931692909217928390556040517f92333b0b676476985757350034668cb9ee247674ac7a7479de10cd761381f7339362000b3c9390049091161515815260200190565b60405180910390a150505050565b6000602081905290815260409020805462000b659062002a96565b80601f016020809104026020016040519081016040528092919081815260200182805462000b939062002a96565b801562000be45780601f1062000bb85761010080835404028352916020019162000be4565b820191906000526020600020905b81548152906001019060200180831162000bc657829003601f168201915b505050505081565b336000908152602081905260408120805482919062000c0b9062002a96565b90501162000c4b5760405162461bcd60e51b815260206004820152600c60248201526b34b73b30b634b2103ab9b2b960a11b604482015260640162000357565b6001600160a01b0383166000908152600160205260409020546001600160801b031662000c8c5760405162461bcd60e51b8152600401620003579062002a6f565b604051632770a7eb60e21b8152336004820152602481018390526001600160a01b03841690639dc29fac90604401600060405180830381600087803b15801562000cd557600080fd5b505af115801562000cea573d6000803e3d6000fd5b505060408051600081526020810190915262000d0e92503391508590859062000fe2565b50600192915050565b600754600160801b900460ff1662000d625760405162461bcd60e51b815260206004820152600d60248201526c696e76616c696420737461746560981b604482015260640162000357565b80516101001462000dab5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420696e7075742073697a6560701b604482015260640162000357565b6000604051806080016040528062000dce60008562000f8090919063ffffffff16565b815260200162000de960208562000f8090919063ffffffff16565b815260200162000dfb84604062000f80565b815260200162000e0d84606062000f80565b81525090506000604051806040016040528062000e3560808662000f8090919063ffffffff16565b815260200162000e478560a062000f80565b81525090506000604051806040016040528062000e6f60c08762000f8090919063ffffffff16565b815260200162000e818660e062000f80565b90529050600062000e996200070e8683608062001682565b60408051608081019182905291925062000ee2919060039060049082845b81548152602001906001019080831162000eb757505050505082856200183e9092919063ffffffff16565b62000f015760405162461bcd60e51b8152600401620003579062002b4c565b62000f0e8285836200183e565b62000f2d5760405162461bcd60e51b8152600401620003579062002b4c565b7f20b54a4e4d72fb59d7f4da768f89618921cb2abc9d2ede08c065bb1f36c745f560038560405162000f6192919062002c01565b60405180910390a162000f786003856004620026b3565b505050505050565b600062000f8f82602062002ae9565b8351101562000fd95760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b604482015260640162000357565b50016020015190565b6001600160a01b038381166000908152600160209081526040808320546001600160801b031683526008825280832054600754948916845291839052822080549193620010f692600160401b9091046001600160401b03169190620010479062002a96565b80601f0160208091040260200160405190810160405280929190818152602001828054620010759062002a96565b8015620010c65780601f106200109a57610100808354040283529160200191620010c6565b820191906000526020600020905b815481529060010190602001808311620010a857829003601f168201915b505050506001600160a01b0389166000908152600160205260409020546001600160801b03169050878762001b08565b90507fdb53e751d28ed0d6e3682814bf8d23f7dd7b29c94f74a56fbb7f88e9dca9f39b8160405162001129919062002a2d565b60405180910390a16200113d848362002b32565b6001600160a01b0386166000908152600160208181526040808420546001600160801b031684526008909152909120919091556007546200119091600160401b9091046001600160401b03169062002b04565b600760086101000a8154816001600160401b0302191690836001600160401b03160217905550505050505050565b6000620011cd82601062002ae9565b83511015620012175760405162461bcd60e51b8152602060048201526015602482015274746f55696e743132385f6f75744f66426f756e647360581b604482015260640162000357565b50016010015190565b60006200122f82600862002ae9565b83511015620012785760405162461bcd60e51b8152602060048201526014602482015273746f55696e7436345f6f75744f66426f756e647360601b604482015260640162000357565b50016008015190565b6000808080620012928686620011be565b90506000816001600160801b031611620012c05760405162461bcd60e51b8152600401620003579062002a6f565b620012cd85601062002ae9565b94506000620012dd878762001d23565b61ffff169050620012f086600262002ae9565b955060208111156200133d5760405162461bcd60e51b8152602060048201526015602482015274696e7465676572206f7574206f6620626f756e647360581b604482015260640162000357565b6000620013b681620013af620013558b8b8762001682565b6200136286602062002b32565b6001600160401b038111156200137c576200137c620027fe565b6040519080825280601f01601f191660200182016040528015620013a7576020820181803683370190505b50906200179b565b9062000f80565b9050620013c4828862002ae9565b989297509550909350505050565b600060608180620013e4868662001d23565b61ffff169050620013f785600262002ae9565b945060006200140887878462001682565b905062001416828762002ae9565b9550600062001426888862001220565b90506200143587600862002ae9565b9891975095509350505050565b6000808062001452858562001d23565b90506200146181601062002c62565b6200146e90600262002c8f565b6200147b90600262002c8f565b9050600062001490868661ffff851662001682565b9050620014a261ffff83168662002ae9565b94506000620014b18262001d84565b95979596505050505050565b600060608180620014cf858262001d23565b9050620014de82600262002ae9565b91506000620014f3868461ffff851662001682565b90506200150561ffff83168462002ae9565b925062001513868462001d23565b91506200152283600262002ae9565b9250600062001537878561ffff861662001682565b90506200154961ffff84168562002ae9565b935060006200156a85868a5162001561919062002b32565b8a919062001682565b905080516044148015620015bb57506001600160801b037f00000000000000000000000000000000bd67087276ce3263b9333aa337e212a416620015b0826000620011be565b6001600160801b0316145b156200166357620015ce81601062001f1a565b6001600160a01b031663ed2e5a97620015e983602462000f80565b6040518263ffffffff1660e01b81526004016200160891815260200190565b60006040518083038186803b1580156200162157600080fd5b505afa15801562001636573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001660919081019062002caf565b90505b6000620016728a858562001f83565b9a91995090975050505050505050565b6060816200169281601f62002ae9565b1015620016d35760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015260640162000357565b620016df828462002ae9565b84511015620017255760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015260640162000357565b60608215801562001746576040519150600082526020820160405262001792565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156200178157805183526020928301920162001767565b5050858452601f01601f1916604052505b50949350505050565b6060806040519050835180825260208201818101602087015b81831015620017ce578051835260209283019201620017b4565b50855184518101855292509050808201602086015b81831015620017fd578051835260209283019201620017e3565b508651929092011591909101601f01601f191660405250905092915050565b62001826620026f6565b6200183882805190602001206200211a565b92915050565b6000806040518061018001604052808660006002811062001863576200186362002d25565b602002015181526020018660016002811062001883576200188362002d25565b602002015181526020017f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c281526020017f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed81526020017f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec81526020017f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d8152602001846000600281106200193b576200193b62002d25565b60200201518152602001846001600281106200195b576200195b62002d25565b60200201518152602001856001600481106200197b576200197b62002d25565b60200201518152602001856000600481106200199b576200199b62002d25565b6020020151815260200185600360048110620019bb57620019bb62002d25565b6020020151815260200185600260048110620019db57620019db62002d25565b602002015190529050620019ee62002714565b60006020826101808560086107d05a03fa905080801562001a0f5762001a11565bfe5b508062001a615760405162461bcd60e51b815260206004820152601d60248201527f424c533a20706172696e6720636865636b2063616c6c206661696c6564000000604482015260640162000357565b5051151595945050505050565b6040805160088082528183019092526060916000919060208201818036833701905050905060c083901b60005b600881101562001aff5781816008811062001aba5762001aba62002d25565b1a60f81b83828151811062001ad35762001ad362002d25565b60200101906001600160f81b031916908160001a9053508062001af68162002d3b565b91505062001a9b565b50909392505050565b6060604482511015801562001b5a57506001600160801b037f00000000000000000000000000000000bd67087276ce3263b9333aa337e212a41662001b4f836000620011be565b6001600160801b0316145b1562001c1a57600062001b6f83601062001f1a565b9050600062001b91604480865162001b88919062002b32565b86919062001682565b90506001600160a01b038216637341a70e62001baf86602462000f80565b836040518363ffffffff1660e01b815260040162001bcf92919062002d59565b600060405180830381600087803b15801562001bea57600080fd5b505af115801562001bff573d6000803e3d6000fd5b5062001c15925086915060009050604462001682565b935050505b600062001c477f00000000000000000000000000000000bd67087276ce3263b9333aa337e212a4620021d2565b905062001c6062001c588862001a6e565b82906200179b565b905062001c7162001c5886620021d2565b905060008062001c818662002263565b9150915062001c9c62001c948262002386565b84906200179b565b925062001caa83836200179b565b925062001cbc62001c94865162002386565b925062001cca83866200179b565b925062001cdb62001c944262001a6e565b925062001ce983896200179b565b60408051600280825281830190925291945062001d1691906020820181803683370190505084906200179b565b9998505050505050505050565b600062001d3282600262002ae9565b8351101562001d7b5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640162000357565b50016002015190565b80516020808301919091206000818152600290925260408220546001600160a01b0316801562001db5579392505050565b600062001dc28562002417565b9050600062001dd18262002496565b6001600160a01b03811660009081526020819052604081208054929350909162001dfb9062002a96565b9050111562001e0d5795945050505050565b600062001e1c836001620024ee565b9050816001600160a01b0316816001600160a01b03161462001e815760405162461bcd60e51b815260206004820152601f60248201527f6d616c666f726d6564207573657220636f6e7472616374206164647265737300604482015260640162000357565b6001600160a01b038216600090815260208181526040909120885162001eaa928a019062002732565b506000858152600260205260409081902080546001600160a01b0319166001600160a01b03851690811790915590517f2451915984c9d5ac7f24f9ef5513c322d23de620a629e29e7a40f2bc117c80849062001f08908a9062002a2d565b60405180910390a25095945050505050565b600062001f2982601462002ae9565b8351101562001f735760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b604482015260640162000357565b500160200151600160601b900490565b6001600160801b0383166000908152600260205260408120546001600160a01b0316801562001fb45790506200040b565b600062001fcc866001600160801b0316868662002508565b9050600062001fdb8262002496565b6001600160a01b0381166000908152600160205260409020549091506001600160801b031615620020115792506200040b915050565b600062002020836001620024ee565b9050816001600160a01b0316816001600160a01b031614620020855760405162461bcd60e51b815260206004820181905260248201527f6d616c666f726d656420617373657420636f6e74726163742061646472657373604482015260640162000357565b6001600160a01b038216600081815260016020908152604080832080546fffffffffffffffffffffffffffffffff19166001600160801b038e16908117909155808452600283529281902080546001600160a01b03191685179055519182527f20df459a0f7f1bc64a42346a9e6536111a3512be01de7a0f5327a4e13b337038910160405180910390a2509695505050505050565b62002124620026f6565b600062002141600080516020620049668339815191528462002d74565b90506000805b6000805160206200496683398151915283840991506000805160206200496683398151915283830991506000805160206200496683398151915260038308915062002192826200258d565b90925090508015620021ae5782845260208401829052620021ca565b6000805160206200496683398151915260018408925062002147565b505050919050565b60408051601080825281830190925260609160009190602082018180368337019050509050608083901b60005b601081101562001aff578181601081106200221e576200221e62002d25565b1a60f81b83828151811062002237576200223762002d25565b60200101906001600160f81b031916908160001a905350806200225a8162002d3b565b915050620021ff565b6040805160208082528183019092526060916000918291602082018180368337019050509050836000805b60208161ffff1610156200234557828161ffff1660208110620022b557620022b562002d25565b1a60f81b848261ffff1681518110620022d257620022d262002d25565b60200101906001600160f81b031916908160001a905350600060f81b848261ffff168151811062002307576200230762002d25565b01602001516001600160f81b03191611801562002326575061ffff8216155b1562002330578091505b806200233c8162002d97565b9150506200228e565b5060006200235582602062002dbc565b90506200237a61ffff83166200236d84602062002dbc565b86919061ffff1662001682565b97909650945050505050565b6040805160028082528183019092526060916000919060208201818036833701905050905060f083901b60005b600281101562001aff57818160028110620023d257620023d262002d25565b1a60f81b838281518110620023eb57620023eb62002d25565b60200101906001600160f81b031916908160001a905350806200240e8162002d3b565b915050620023b3565b60606000604051806020016200242d90620027ae565b6020820181038252601f19601f82011660405250905060008360405160200162002458919062002a2d565b604051602081830303815290604052905081816040516020016200247e92919062002de2565b60405160208183030381529060405292505050919050565b8051602091820120604080516001600160f81b0319818501523060601b6bffffffffffffffffffffffff1916602182015260016035820152605580820193909352815180820390930183526075019052805191012090565b6000808284516020860134f59050803b6200040b57600080fd5b60606000604051806020016200251e90620027bc565b6020820181038252601f19601f82011660405250905060008584866040516020016200254d9392919062002e0c565b604051602081830303815290604052905081816040516020016200257392919062002de2565b604051602081830303815290604052925050509392505050565b600080600060405160208152602080820152602060408201528460608201527f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f5260808201526000805160206200496683398151915260a082015260208160c08360056107d05a03fa915081801562001a0f5750519250600080516020620049668339815191528380098414915080620026695760405162461bcd60e51b815260206004820152601c60248201527f424c533a2073717274206d6f646578702063616c6c206661696c656400000000604482015260640162000357565b50915091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a081019190915260c08101620026ae620026f6565b905290565b8260048101928215620026e4579160200282015b82811115620026e4578251825591602001919060010190620026c7565b50620026f2929150620027ca565b5090565b60405180604001604052806002906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b828054620027409062002a96565b90600052602060002090601f016020900481019282620027645760008555620026e4565b82601f106200277f57805160ff1916838001178555620026e4565b82800160010185558215620026e45791820182811115620026e4578251825591602001919060010190620026c7565b610d2d8062002e4683390190565b610df38062003b7383390190565b5b80821115620026f25760008155600101620027cb565b80356001600160a01b0381168114620027f957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200283f576200283f620027fe565b604052919050565b60006001600160401b03821115620028635762002863620027fe565b50601f01601f191660200190565b600082601f8301126200288357600080fd5b81356200289a620028948262002847565b62002814565b818152846020838601011115620028b057600080fd5b816020850160208301376000918101602001919091529392505050565b600080600060608486031215620028e357600080fd5b620028ee84620027e1565b92506020840135915060408401356001600160401b038111156200291157600080fd5b6200291f8682870162002871565b9150509250925092565b6000602082840312156200293c57600080fd5b5035919050565b6000602082840312156200295657600080fd5b81356001600160401b038111156200296d57600080fd5b6200297b8482850162002871565b949350505050565b6000602082840312156200299657600080fd5b81356001600160801b03811681146200040b57600080fd5b600060208284031215620029c157600080fd5b6200040b82620027e1565b60005b83811015620029e9578181015183820152602001620029cf565b83811115620029f9576000848401525b50505050565b6000815180845262002a19816020860160208601620029cc565b601f01601f19169290920160200192915050565b6020815260006200040b6020830184620029ff565b6000806040838503121562002a5657600080fd5b62002a6183620027e1565b946020939093013593505050565b6020808252600d908201526c1a5b9d985b1a5908185cdcd95d609a1b604082015260600190565b600181811c9082168062002aab57607f821691505b6020821081141562002acd57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111562002aff5762002aff62002ad3565b500190565b60006001600160401b0380831681851680830382111562002b295762002b2962002ad3565b01949350505050565b60008282101562002b475762002b4762002ad3565b500390565b602080825260119082015270696e76616c6964207369676e617475726560781b604082015260600190565b83815260606020820152600062002b926060830185620029ff565b90506001600160401b0383166040830152949350505050565b60018060a01b038416815282602082015260606040820152600062002bd46060830184620029ff565b95945050505050565b60006020828403121562002bf057600080fd5b815180151581146200040b57600080fd5b6101008101818460005b600481101562002c2c57815483526020909201916001918201910162002c0b565b505050608082018360005b600481101562002c5857815183526020928301929091019060010162002c37565b5050509392505050565b600061ffff8083168185168183048111821515161562002c865762002c8662002ad3565b02949350505050565b600061ffff80831681851680830382111562002b295762002b2962002ad3565b60006020828403121562002cc257600080fd5b81516001600160401b0381111562002cd957600080fd5b8201601f8101841362002ceb57600080fd5b805162002cfc620028948262002847565b81815285602083850101111562002d1257600080fd5b62002bd4826020830160208601620029cc565b634e487b7160e01b600052603260045260246000fd5b600060001982141562002d525762002d5262002ad3565b5060010190565b8281526040602082015260006200297b6040830184620029ff565b60008262002d9257634e487b7160e01b600052601260045260246000fd5b500690565b600061ffff8083168181141562002db25762002db262002ad3565b6001019392505050565b600061ffff8381169083168181101562002dda5762002dda62002ad3565b039392505050565b6000835162002df6818460208801620029cc565b83519083019062002b29818360208801620029cc565b83815260606020820152600062002e276060830185620029ff565b828103604084015262002e3b8185620029ff565b969550505050505056fe60806040523480156200001157600080fd5b5060405162000d2d38038062000d2d83398101604081905262000034916200011f565b600080546001600160a01b0319163317905580516200005b90600190602084019062000063565b505062000238565b8280546200007190620001fb565b90600052602060002090601f016020900481019282620000955760008555620000e0565b82601f10620000b057805160ff1916838001178555620000e0565b82800160010185558215620000e0579182015b82811115620000e0578251825591602001919060010190620000c3565b50620000ee929150620000f2565b5090565b5b80821115620000ee5760008155600101620000f3565b634e487b7160e01b600052604160045260246000fd5b600060208083850312156200013357600080fd5b82516001600160401b03808211156200014b57600080fd5b818501915085601f8301126200016057600080fd5b81518181111562000175576200017562000109565b604051601f8201601f19908116603f01168101908382118183101715620001a057620001a062000109565b816040528281528886848701011115620001b957600080fd5b600093505b82841015620001dd5784840186015181850187015292850192620001be565b82841115620001ef5760008684830101525b98975050505050505050565b600181811c908216806200021057607f821691505b602082108114156200023257634e487b7160e01b600052602260045260246000fd5b50919050565b610ae580620002486000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637b103999146100465780637ceba01814610076578063bdd4d18d14610099575b600080fd5b600054610059906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b610089610084366004610855565b6100ae565b604051901515815260200161006d565b6100a161035e565b60405161006d919061098a565b600080546001600160a01b031633146100fd5760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064015b60405180910390fd5b601c8251101561019757600054604051635569f64b60e11b81526001600160a01b038681166004830152602482018690529091169063aad3ec9690604401602060405180830381600087803b15801561015557600080fd5b505af1158015610169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061018d919061099d565b5060019050610357565b60006101a383826103ec565b905060018161ffff1610806101bc575060108161ffff16115b1561025257600054604051635569f64b60e11b81526001600160a01b038781166004830152602482018790529091169063aad3ec9690604401602060405180830381600087803b15801561020f57600080fd5b505af1158015610223573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610247919061099d565b506001915050610357565b60025b83518110156102c757600081600214905060006102818384885161027991906109d5565b889190610449565b9050600080610292838b8b87610556565b91509150806102a457505050506102c7565b6102ae82866109ec565b94505050505081806102bf90610a04565b925050610255565b50600054604051635569f64b60e11b81526001600160a01b038781166004830152602482018790529091169063aad3ec9690604401602060405180830381600087803b15801561031657600080fd5b505af1925050508015610346575060408051601f3d908101601f191682019092526103439181019061099d565b60015b61034f57610351565b505b60019150505b9392505050565b6001805461036b90610a22565b80601f016020809104026020016040519081016040528092919081815260200182805461039790610a22565b80156103e45780601f106103b9576101008083540402835291602001916103e4565b820191906000526020600020905b8154815290600101906020018083116103c757829003601f168201915b505050505081565b60006103f98260026109ec565b835110156104405760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b60448201526064016100f4565b50016002015190565b60608161045781601f6109ec565b10156104965760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016100f4565b6104a082846109ec565b845110156104e45760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016100f4565b606082158015610503576040519150600082526020820160405261054d565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561053c578051835260209283019201610524565b5050858452601f01601f1916604052505b50949350505050565b6000806000865181601461056a91906109ec565b111561057b579150600090506107d1565b600061058788836107da565b90506105948260146109ec565b915084156106a35760405163095ea7b360e01b81526001600160a01b0382811660048301526000602483015288169063095ea7b390604401602060405180830381600087803b1580156105e657600080fd5b505af11580156105fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061e919061099d565b5060405163095ea7b360e01b81526001600160a01b0382811660048301526024820188905288169063095ea7b390604401602060405180830381600087803b15801561066957600080fd5b505af115801561067d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a1919061099d565b505b87516106b08360026109ec565b11156106c257509150600090506107d1565b60006106ce89846103ec565b61ffff1690506106df8360026109ec565b89519093506106ee82856109ec565b111561070357826000945094505050506107d1565b60006107108a8584610449565b9050600080846001600160a01b03168360405161072d9190610a5d565b6000604051808303816000865af19150503d806000811461076a576040519150601f19603f3d011682016040523d82523d6000602084013e61076f565b606091505b50909250905061077f84876109ec565b9550846001600160a01b03167f374b40ceb7994eb007a897f9cafaa351e1e66f4dba809f52995372acc1f12d308484846040516107be93929190610a79565b60405180910390a2509395509293505050505b94509492505050565b60006107e78260146109ec565b8351101561082f5760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b60448201526064016100f4565b500160200151600160601b900490565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561086a57600080fd5b83356001600160a01b038116811461088157600080fd5b925060208401359150604084013567ffffffffffffffff808211156108a557600080fd5b818601915086601f8301126108b957600080fd5b8135818111156108cb576108cb61083f565b604051601f8201601f19908116603f011681019083821181831017156108f3576108f361083f565b8160405282815289602084870101111561090c57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60005b83811015610949578181015183820152602001610931565b83811115610958576000848401525b50505050565b6000815180845261097681602086016020860161092e565b601f01601f19169290920160200192915050565b602081526000610357602083018461095e565b6000602082840312156109af57600080fd5b8151801515811461035757600080fd5b634e487b7160e01b600052601160045260246000fd5b6000828210156109e7576109e76109bf565b500390565b600082198211156109ff576109ff6109bf565b500190565b600061ffff821680610a1857610a186109bf565b6000190192915050565b600181811c90821680610a3657607f821691505b60208210811415610a5757634e487b7160e01b600052602260045260246000fd5b50919050565b60008251610a6f81846020870161092e565b9190910192915050565b606081526000610a8c606083018661095e565b84151560208401528281036040840152610aa6818561095e565b969550505050505056fea265627a7a7231582092fbf7a05fe947ca227e879053d3cd676116b315b5dc2c6169168c1a6fea99f664736f6c6343000809003260a06040523480156200001157600080fd5b5060405162000df338038062000df38339810160408190526200003491620001fb565b600080546001600160a01b031916331790556001600160801b03831660805281516200006890600390602085019062000088565b5080516200007e90600490602084019062000088565b50505050620002c2565b828054620000969062000285565b90600052602060002090601f016020900481019282620000ba576000855562000105565b82601f10620000d557805160ff191683800117855562000105565b8280016001018555821562000105579182015b8281111562000105578251825591602001919060010190620000e8565b506200011392915062000117565b5090565b5b8082111562000113576000815560010162000118565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200015657600080fd5b81516001600160401b03808211156200017357620001736200012e565b604051601f8301601f19908116603f011681019082821181831017156200019e576200019e6200012e565b81604052838152602092508683858801011115620001bb57600080fd5b600091505b83821015620001df5785820183015181830184015290820190620001c0565b83821115620001f15760008385830101525b9695505050505050565b6000806000606084860312156200021157600080fd5b83516001600160801b03811681146200022957600080fd5b60208501519093506001600160401b03808211156200024757600080fd5b620002558783880162000144565b935060408601519150808211156200026c57600080fd5b506200027b8682870162000144565b9150509250925092565b600181811c908216806200029a57607f821691505b60208210811415620002bc57634e487b7160e01b600052602260045260246000fd5b50919050565b608051610b15620002de60003960006102230152610b156000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c5780639dc29fac116100665780639dc29fac146101f8578063a9059cbb1461020b578063af640d0f1461021e578063dd62ed3e1461026657600080fd5b806370a082311461019c5780637b103999146101c557806395d89b41146101f057600080fd5b80631f6847fe116100c85780631f6847fe1461014757806323b872dd1461015a578063313ce5671461016d57806340c10f191461018757600080fd5b806306fdde03146100ef578063095ea7b31461010d57806318160ddd14610130575b600080fd5b6100f761029f565b604051610104919061084a565b60405180910390f35b61012061011b366004610879565b61032d565b6040519015158152602001610104565b61013960055481565b604051908152602001610104565b6101206101553660046108b9565b610412565b610120610168366004610984565b6104b0565b610175600881565b60405160ff9091168152602001610104565b61019a610195366004610879565b6104fb565b005b6101396101aa3660046109c0565b6001600160a01b031660009081526001602052604090205490565b6000546101d8906001600160a01b031681565b6040516001600160a01b039091168152602001610104565b6100f76105db565b61019a610206366004610879565b6105e8565b610120610219366004610879565b6106c1565b6102457f000000000000000000000000000000000000000000000000000000000000000081565b6040516fffffffffffffffffffffffffffffffff9091168152602001610104565b6101396102743660046109db565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b600380546102ac90610a0e565b80601f01602080910402602001604051908101604052809291908181526020018280546102d890610a0e565b80156103255780601f106102fa57610100808354040283529160200191610325565b820191906000526020600020905b81548152906001019060200180831161030857829003601f168201915b505050505081565b600081158061035d57503360009081526002602090815260408083206001600160a01b0387168452909152902054155b6103ae5760405162461bcd60e51b815260206004820152601f60248201527f617070726f7665206f6e2061206e6f6e2d7a65726f20616c6c6f77616e63650060448201526064015b60405180910390fd5b3360008181526002602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b600061041f3385856106e5565b6000546040516344d1718760e01b81526001600160a01b03909116906344d171879061045390879087908790600401610a49565b602060405180830381600087803b15801561046d57600080fd5b505af1158015610481573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a59190610a79565b506001949350505050565b60006104bd84848461079a565b600080546040805192835260208301908190526344d1718760e01b90526001600160a01b0316906344d1718790610453908690869060248101610a49565b6000546001600160a01b031633146105445760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610568908290610ab1565b6001600160a01b03831660009081526001602052604090205560055461058f908290610ab1565b6005556000546040518281526001600160a01b038481169216907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b600480546102ac90610a0e565b6000546001600160a01b031633146106315760405162461bcd60e51b815260206004820152600c60248201526b6e6f7420726567697374727960a01b60448201526064016103a5565b6001600160a01b038216600090815260016020526040902054610655908290610ac9565b6001600160a01b03831660009081526001602052604090205560055461067c908290610ac9565b6005556000546040518281526001600160a01b03918216918416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016105cf565b604080516000808252602082019092526106de9084908490610412565b9392505050565b6001600160a01b038316600090815260016020526040902054610709908290610ac9565b6001600160a01b038085166000908152600160205260408082209390935590841681522054610739908290610ab1565b6001600160a01b0380841660008181526001602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061078d9085815260200190565b60405180910390a3505050565b6001600160a01b03831660009081526002602090815260408083203384529091529020546107c88282610ac9565b6001600160a01b03851660009081526002602090815260408083203384529091529020556107f78484846106e5565b50505050565b6000815180845260005b8181101561082357602081850181015186830182015201610807565b81811115610835576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006106de60208301846107fd565b80356001600160a01b038116811461087457600080fd5b919050565b6000806040838503121561088c57600080fd5b6108958361085d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156108ce57600080fd5b6108d78461085d565b925060208401359150604084013567ffffffffffffffff808211156108fb57600080fd5b818601915086601f83011261090f57600080fd5b813581811115610921576109216108a3565b604051601f8201601f19908116603f01168101908382118183101715610949576109496108a3565b8160405282815289602084870101111561096257600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060006060848603121561099957600080fd5b6109a28461085d565b92506109b06020850161085d565b9150604084013590509250925092565b6000602082840312156109d257600080fd5b6106de8261085d565b600080604083850312156109ee57600080fd5b6109f78361085d565b9150610a056020840161085d565b90509250929050565b600181811c90821680610a2257607f821691505b60208210811415610a4357634e487b7160e01b600052602260045260246000fd5b50919050565b60018060a01b0384168152826020820152606060408201526000610a7060608301846107fd565b95945050505050565b600060208284031215610a8b57600080fd5b815180151581146106de57600080fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115610ac457610ac4610a9b565b500190565b600082821015610adb57610adb610a9b565b50039056fea265627a7a72315820e4d33a6aec92022b9335cb5ab741e8642db27bf8eedbdc8f2e4317e41206159964736f6c6343000809003230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47a265627a7a723158206a8dd884554f3e66fede647c63be615457016e4d43ad521e57f0e9934dcb034864736f6c63430008090032