false
true
0

Contract Address Details

0x80493D07ddfcE7a8b507C407459935a88C62Ad8E

Contract Name
Random
Creator
0xaf2ce0–4ab9b0 at 0xb7a99e–92dbf8
Balance
0 tPLS
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
25428762
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Random




Optimization enabled
false
Compiler version
v0.8.25+commit.b61c2a91




EVM Version
cancun




Verified at
2024-08-13T21:15:38.803732Z

contracts/Random.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {SSTORE2} from "solady/src/utils/SSTORE2.sol";
import {LibPRNG} from "solady/src/utils/LibPRNG.sol";
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
import {EfficientHashLib} from "solady/src/utils/EfficientHashLib.sol";
import {LibMulticaller} from "multicaller/src/LibMulticaller.sol";
import {IRandom} from "./implementations/IRandom.sol";
import {PreimageLocation} from "./PreimageLocation.sol";
import {Errors, Cast, Reveal, Ink, Heat, Start, Expired, Chop, Bleach} from "./Constants.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {SlotDerivation} from "./SlotDerivation.sol";

contract Random is IRandom {
    // this error is used inside of sstore to so we surface it here so that it sticks in the abi
    using SSTORE2 for address;
    using SSTORE2 for bytes;

    using SafeTransferLib for address;

    using StorageSlot for bytes32;
    using StorageSlot for StorageSlot.Bytes32SlotType;
    using SlotDerivation for *;

    using LibPRNG for LibPRNG.PRNG;

    using EfficientHashLib for bytes32;
    using EfficientHashLib for bytes32[];

    using PreimageLocation for PreimageLocation.Info;

    string private constant _NAMESPACE = "random";

    mapping(address account => bytes32 latest) internal _latest;
    mapping(address account => mapping(address token => uint256 amount)) internal _custodied;
    mapping(address provider => mapping(address token => mapping(uint256 price => uint256 max))) internal _preimageCount;
    mapping(
        address provider
            => mapping(address token => mapping(uint256 price => mapping(uint256 offset => address pointer)))
    ) internal _pointers;
    mapping(
        address provider
            => mapping(address token => mapping(uint256 price => mapping(uint256 index => uint256 accessFlags)))
    ) internal _accessFlags;
    mapping(
        address provider
            => mapping(address token => mapping(uint256 price => mapping(uint256 index => bytes32 formerSecret)))
    ) internal _formerSecret;

    /**
     * start the process to reveal the ink that was written (using invisible ink as a visual analogy)
     * @dev the reason why this method uses flags (256 per slot) is because this allows a
     * central entity to benefit from requesting randomness such as an eip3074 enabled multicaller
     * and benefit greatly from the gas savings of access the same slot up to 256 times
     * @dev notice that the index is derived from the preimage key by adding [95..16] and [15..1] together
     */
    function _ignite(PreimageLocation.Info memory nfo, bytes32 section) internal returns (bool) {
        unchecked {
            if (_consumed(nfo)) {
                return false;
            }
            _accessFlags[nfo.provider][nfo.token][nfo.price][(nfo.offset + nfo.index) / TWO_FIVE_SIX] |=
                (ONE << ((nfo.offset + nfo.index) % TWO_FIVE_SIX));
            emit Heat(nfo.provider, section, nfo.offset + nfo.index);
            return true;
        }
    }

    function _consumed(PreimageLocation.Info memory nfo) internal view returns (bool) {
        if (_pointerSize(nfo) / THREE_TWO <= nfo.index) {
            revert Errors.Misconfigured();
        }
        // returning zero means that the secret has not been requested yet on chain
        uint256 section = _accessFlags[nfo.provider][nfo.token][nfo.price][(nfo.index + nfo.offset) / TWO_FIVE_SIX];
        return (section << (TWO_FIVE_FIVE - ((nfo.index + nfo.offset) % TWO_FIVE_SIX)) >> TWO_FIVE_FIVE) == ONE;
    }

    function _pointerSize(PreimageLocation.Info memory nfo) internal view returns (uint256 size) {
        address pntr = _pointers[nfo.provider][nfo.token][nfo.price][nfo.offset];
        if (pntr == address(0)) {
            revert Errors.Misconfigured();
        }
        assembly {
            size := extcodesize(pntr)
        }
    }

    function _flick(PreimageLocation.Info calldata nfo, bytes32 formerSecret)
        internal
        returns (bytes32 location, bool first)
    {
        unchecked {
            address pntr = _pointers[nfo.provider][nfo.token][nfo.price][nfo.offset];
            if (pntr == address(0)) {
                revert Errors.Misconfigured();
            }
            // length check is skipped because if one goes out of bounds you either err
            // or you end up with zero bytes, which would be quite the feat to find the hash for
            // always read 32 bytes
            if (
                formerSecret.hash()
                    != bytes32(pntr.read((nfo.index * THREE_TWO), ((nfo.index * THREE_TWO) + THREE_TWO)))
            ) {
                revert Errors.SecretMismatch();
            }
            // only ever set once but do not penalize for lack of coordination
            location = nfo.hash();
            if (_secret(nfo) == bytes32(ZERO)) {
                _formerSecret[nfo.provider][nfo.token][nfo.price][nfo.offset + nfo.index] = formerSecret;
                emit Reveal(nfo.provider, location, formerSecret);
                return (location, true);
            }
            return (location, false);
        }
    }

    function _cast(bytes32 key, PreimageLocation.Info[] calldata preimageInfo, bytes32[] memory revealedSecrets)
        internal
        returns (bool)
    {
        unchecked {
            uint256 i;
            uint256 len = preimageInfo.length;
            bytes32 seed = _seed[key];
            if (seed != bytes32(ZERO)) {
                return false;
            }
            bytes32[] memory locations = new bytes32[](len);
            uint256 firstFlicks;
            bool first;
            bool missing;
            do {
                if (revealedSecrets[i] != bytes32(0)) {
                    (locations[i], first) = _flick(preimageInfo[i], revealedSecrets[i]);
                    if (first) {
                        ++firstFlicks;
                    }
                } else {
                    revealedSecrets[i] = _secret(preimageInfo[i]);
                    if (revealedSecrets[i] == bytes32(ZERO)) {
                        missing = true;
                    }
                }
                ++i;
            } while (i < len);
            if (missing) {
                _timeline[key] += firstFlicks;
                return false;
            }
            if (key != _toId(locations.hash(), locations.length)) {
                revert Errors.NotInCohort();
            }
            _timeline[key] += firstFlicks;
            // mark as generated
            seed = revealedSecrets.hash();
            _seed[key] = seed;
            emit Cast(key, seed);
            _scatter(key, preimageInfo);
            return true;
        }
    }

    function _secret(PreimageLocation.Info calldata info) internal view returns (bytes32) {
        return _formerSecret[info.provider][info.token][info.price][info.offset + info.index];
    }

    function _toId(bytes32 hashed, uint256 len) internal pure returns (bytes32) {
        unchecked {
            return bytes32((uint256(hashed) << EIGHT) | uint256(uint8(len)));
        }
    }

    function _distribute(address recipient, address token, uint256 amount) internal {
        if (amount == ZERO) return;
        if (token == address(0)) {
            recipient.safeTransferETH(amount);
        } else {
            token.safeTransfer(recipient, amount);
        }
    }

    function _scatter(bytes32 key, PreimageLocation.Info[] calldata info) internal {
        unchecked {
            uint256 len = info.length;
            PreimageLocation.Info calldata item = info[_random(key, len)];
            uint256 total;
            uint256 i;
            do {
                total += item.price;
                ++i;
            } while (i < len);
            if (_expired(_timeline[key])) {
                address ender = LibMulticaller.senderOrSigner();
                uint256 expiredCallerPayout = total / 2; // take half if cast happens late
                _custodied[ender][item.token] += expiredCallerPayout;
                total -= expiredCallerPayout;
                // can be used as reputation
                emit Expired(item.provider, ender, key);
            }
            _custodied[item.provider][item.token] += total;
        }
    }

    function _receiveTokens(address account, address token, uint256 amount) internal returns (uint256) {
        unchecked {
            if (token == address(0)) {
                if (amount > msg.value) {
                    revert Errors.MissingPayment();
                }
                amount = msg.value;
            } else {
                // because we do not check balanceof delta, we will
                // not correctly attribute tax/reflection tokens
                uint256 before = token.balanceOf(address(this));
                token.safeTransferFrom2(account, address(this), amount);
                amount = token.balanceOf(address(this)) - before;
            }
            return amount;
        }
    }

    function _attributePushedValue(address owner) internal {
        unchecked {
            if (msg.value > ZERO) {
                _custodied[owner][address(0)] += msg.value;
            }
        }
    }

    function _decrementValue(address account, address token, uint256 desired) internal returns (uint256 delta) {
        unchecked {
            uint256 limit = _custodied[account][token];
            delta = desired > limit ? limit : desired;
            if (delta > ZERO) {
                _custodied[account][token] = limit - delta;
            }
        }
    }

    function balanceOf(address account, address token) external view returns (uint256) {
        return _custodied[account][token];
    }

    function randomness(bytes32 key) external view override returns (Randomness memory) {
        return Randomness({timeline: _timeline[key], seed: _seed[key]});
    }

    function latest(address owner, bool onlySameTx) external view override returns (bytes32 key) {
        key = _NAMESPACE.erc7201Slot().deriveMapping(owner).asBytes32().tload();
        if (key == bytes32(ZERO)) {
            if (onlySameTx) {
                revert Errors.UnableToService();
            }
            key = _latest[owner];
        }
    }

    function consumed(PreimageLocation.Info calldata nfo) external view override returns (bool) {
        return _consumed(nfo);
    }

    function heat(
        uint256 required,
        uint256 expiryOffset,
        address token,
        PreimageLocation.Info[] calldata potentialLocations
    ) external payable override returns (bytes32) {
        unchecked {
            bytes32[] memory locations = new bytes32[](required);
            address account = LibMulticaller.senderOrSigner();
            {
                _attributePushedValue(account);
                if (required == ZERO || required > TWO_FIVE_FIVE || required > potentialLocations.length) {
                    // only 254 len or fewer allowed
                    revert Errors.UnableToService();
                }
                uint256 len = potentialLocations.length;
                uint256 i;
                uint256 contributing;
                uint256 amount;
                do {
                    // non zero means that the value exists
                    if (
                        token == potentialLocations[i].token
                            && _ignite(potentialLocations[i], potentialLocations[i].section())
                    ) {
                        locations[contributing] = potentialLocations[i].hash();
                        amount += potentialLocations[i].price;
                        ++contributing;
                        if (required == contributing) {
                            break;
                        }
                    }
                    ++i;
                } while (i < len);

                if (contributing < required) {
                    // let other contracts revert if they must
                    revert Errors.UnableToService();
                }
                if (amount > ZERO && amount > _decrementValue(account, token, amount)) {
                    revert Errors.MissingPayment();
                }
            }
            {
                bytes32 key = _toId(locations.hash(), locations.length);
                // front load the cost of requesting randomness
                // put it on the shoulders of the consumer
                // this can probably be optimized
                _timeline[key] = _timelineFromInputs({
                    owner: account,
                    expiryOffset: expiryOffset,
                    start: expiryOffset << TWO_FIVE_FIVE == ZERO ? block.number : block.timestamp
                });
                _NAMESPACE.erc7201Slot().deriveMapping(account).asBytes32().tstore(key);
                _latest[account] = key;
                emit Start(account, key);
                return key;
            }
        }
    }

    function _timelineFromInputs(address owner, uint256 expiryOffset, uint256 start) internal pure returns (uint256) {
        return (uint256(uint160(owner)) << NINE_SIX) | (uint256((uint48(start))) << FOUR_EIGHT)
            | (uint256(uint40(expiryOffset)) << EIGHT); // last 8 bits left blank for counting
    }

    /**
     * @param info access the pointer as defined by the preimage location
     * @return pointer the address that holds preimages
     */
    function pointer(PreimageLocation.Info calldata info) external view override returns (address) {
        return _pointers[info.provider][info.token][info.price][info.offset];
    }

    /**
     * provide stored randomness for the future. imagine painting a die with invisible ink
     * @param data the concatenated, immutable preimages to write on chain
     * @dev if data length is > (24576-32), then this method will fail
     * @dev it is best to call this infrequently but to do so with as
     * much calldata as possible to increase gas savings for randomness providers
     */
    function ink(address token, uint256 price, bytes calldata data) external payable {
        unchecked {
            uint256 count = data.length / THREE_TWO;
            if (data.length == ZERO || data.length % THREE_TWO != ZERO) {
                revert Errors.Misconfigured();
            }
            address provider = LibMulticaller.senderOrSigner();
            _attributePushedValue(provider);
            uint256 start = _preimageCount[provider][token][price];
            address pntr = data.write();
            // over an address's lifetime, it can write up to 2^32 preimages
            // currently the count will be limited to 24_576/32=768 per _ink call, but future updates
            // could improve this, so 16 bits are allocated for that situation (up to 65_535)
            _pointers[provider][token][price][start] = pntr;
            _preimageCount[provider][token][price] = start + count;
            emit Ink(provider, (start << ONE_TWO_EIGHT) | (start + count), pntr);
        }
    }

    function chop(bytes32 key, PreimageLocation.Info[] calldata preimageInfo) external payable {
        unchecked {
            address signer = LibMulticaller.senderOrSigner();
            if (signer != address(uint160(_timeline[key] >> NINE_SIX))) {
                revert Errors.SignerMismatch();
            }
            _attributePushedValue(signer);
            if (_seed[key] != bytes32(ZERO)) {
                // don't penalize, because a provider could slip in before
                return;
            }
            uint256 total;
            uint256 i;
            uint256 len = preimageInfo.length;
            do {
                total += preimageInfo[i].price;
                ++i;
            } while (i < len);
            _custodied[signer][preimageInfo[ZERO].token] += total;
            emit Chop(key);
        }
    }

    function cast(bytes32 key, PreimageLocation.Info[] calldata preimageInfo, bytes32[] calldata revealed)
        external
        payable
        returns (bool)
    {
        unchecked {
            if (msg.value > ZERO) {
                _attributePushedValue(LibMulticaller.senderOrSigner());
            }
            return _cast(key, preimageInfo, revealed);
        }
    }

    function _random(bytes32 key, uint256 upper) internal view returns (uint256) {
        return LibPRNG.PRNG({state: uint256(_seed[key])}).uniform(upper);
    }

    function handoff(address recipient, address token, int256 amount) external payable {
        unchecked {
            address account = LibMulticaller.senderOrSigner();
            recipient = recipient == address(0) ? account : recipient;
            if (amount < 0) {
                // move take tokens from signer to recipient custodied by signer
                _custodied[recipient][token] += _receiveTokens(account, token, uint256(-amount));
            } else {
                // move tokens from signer to recipient custodied by contract
                _distribute(recipient, token, _decrementValue(account, token, uint256(amount)));
            }
        }
    }
    /**
     * when a provider no longer has access to appropriate data, he should
     * invalidate the data that he has written so that he does not confuse front ends
     */

    function bleach(PreimageLocation.Info memory info) external payable {
        unchecked {
            address provider = LibMulticaller.senderOrSigner();
            _attributePushedValue(provider);
            if (provider != info.provider) {
                revert Errors.SignerMismatch();
            }
            uint256 size = _pointerSize(info) / THREE_TWO;
            size /= THREE_TWO;
            bytes32 section = info.section();
            emit Bleach(provider, section);
            // consumes a whole pointer
            uint256 i;
            do {
                info.index = i;
                _ignite(info, section);
                ++i;
            } while (i < size);
        }
    }
}
        

contracts/Constants.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

event Ok(address indexed provider, bytes32 section);

event Bleach(address indexed provider, bytes32 section);

event Reprice(address indexed provider, uint256 pricePer);

event Ink(address indexed provider, uint256 offset, address pointer);

event Heat(address indexed provider, bytes32 section, uint256 index);

event Start(address indexed owner, bytes32 key); // no need to index because all keys should be unique

event Reveal(address indexed provider, bytes32 location, bytes32 formerSecret);

event Expired(address indexed recipient, address indexed ender, bytes32 key);

event FundingScattered(address indexed recipient, uint256 amount, bytes32 key);

event Cast(bytes32 key, bytes32 seed);

event Chop(bytes32 key);

abstract contract Errors {
    error DeploymentFailed();
    error Misconfigured();
    error UnableToService();
    error MissingPayment();
    error SecretMismatch();
    error ZeroSecret();
    error NotInCohort();
    error SignerMismatch();
}
          

contracts/PreimageLocation.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {EfficientHashLib} from "solady/src/utils/EfficientHashLib.sol";

library PreimageLocation {
    struct Info {
        address provider;
        address token;
        uint256 price;
        uint256 offset;
        uint256 index;
    }

    function hash(Info memory info) internal pure returns (bytes32) {
        return EfficientHashLib.hash(
            bytes32(uint256(uint160(info.provider))),
            bytes32(uint256(uint160(info.token))),
            bytes32(info.price),
            bytes32(info.offset),
            bytes32(info.index)
        );
    }

    function section(Info memory info) internal pure returns (bytes32) {
        return EfficientHashLib.hash(
            bytes32(uint256(uint160(info.provider))),
            bytes32(uint256(uint160(info.token))),
            bytes32(info.price),
            bytes32(info.offset)
        );
    }
}
          

contracts/SlotDerivation.sol

// SPDX-License-Identifier: MIT
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.

pragma solidity ^0.8.24;

/**
 * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
 * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
 * the solidity language / compiler.
 *
 * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
 *
 * Example usage:
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using StorageSlot for bytes32;
 *     using SlotDerivation for bytes32;
 *
 *     // Declare a namespace
 *     string private constant _NAMESPACE = "<namespace>" // eg. OpenZeppelin.Slot
 *
 *     function setValueInNamespace(uint256 key, address newValue) internal {
 *         _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
 *     }
 *
 *     function getValueInNamespace(uint256 key) internal view returns (address) {
 *         return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {StorageSlot}.
 *
 * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
 * upgrade safety will ignore the slots accessed through this library.
 */
library SlotDerivation {
    /**
     * @dev Derive an ERC-7201 slot from a string (namespace).
     */
    function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
            slot := and(keccak256(0x00, 0x20), not(0xff))
        }
    }

    // /**
    //  * @dev Add an offset to a slot to get the n-th element of a structure or an array.
    //  */
    // function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
    //     unchecked {
    //         return bytes32(uint256(slot) + pos);
    //     }
    // }

    // /**
    //  * @dev Derive the location of the first element in an array from the slot where the length is stored.
    //  */
    // function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         mstore(0x00, slot)
    //         result := keccak256(0x00, 0x20)
    //     }
    // }

    /**
     * @dev Derive the location of a mapping element from the key.
     */
    function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, key)
            mstore(0x20, slot)
            result := keccak256(0x00, 0x40)
        }
    }

    // /**
    //  * @dev Derive the location of a mapping element from the key.
    //  */
    // function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         mstore(0x00, key)
    //         mstore(0x20, slot)
    //         result := keccak256(0x00, 0x40)
    //     }
    // }

    // /**
    //  * @dev Derive the location of a mapping element from the key.
    //  */
    // function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         mstore(0x00, key)
    //         mstore(0x20, slot)
    //         result := keccak256(0x00, 0x40)
    //     }
    // }

    // /**
    //  * @dev Derive the location of a mapping element from the key.
    //  */
    // function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         mstore(0x00, key)
    //         mstore(0x20, slot)
    //         result := keccak256(0x00, 0x40)
    //     }
    // }

    // /**
    //  * @dev Derive the location of a mapping element from the key.
    //  */
    // function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         mstore(0x00, key)
    //         mstore(0x20, slot)
    //         result := keccak256(0x00, 0x40)
    //     }
    // }

    // /**
    //  * @dev Derive the location of a mapping element from the key.
    //  */
    // function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         let length := mload(key)
    //         let begin := add(key, 0x20)
    //         let end := add(begin, length)
    //         let cache := mload(end)
    //         mstore(end, slot)
    //         result := keccak256(begin, add(length, 0x20))
    //         mstore(end, cache)
    //     }
    // }

    // /**
    //  * @dev Derive the location of a mapping element from the key.
    //  */
    // function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
    //     /// @solidity memory-safe-assembly
    //     assembly {
    //         let length := mload(key)
    //         let begin := add(key, 0x20)
    //         let end := add(begin, length)
    //         let cache := mload(end)
    //         mstore(end, slot)
    //         result := keccak256(begin, add(length, 0x20))
    //         mstore(end, cache)
    //     }
    // }
}
          

contracts/StorageSlot.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.24;

library StorageSlot {
    struct Bytes32Slot {
        bytes32 value;
    }
    /**
     * @dev UDVT that represent a slot holding a bytes32.
     */

    type Bytes32SlotType is bytes32;

    /**
     * @dev Cast an arbitrary slot to a Bytes32SlotType.
     */
    function asBytes32(bytes32 slot) internal pure returns (Bytes32SlotType) {
        return Bytes32SlotType.wrap(slot);
    }
    /**
     * @dev Load the value held at location `slot` in transient storage.
     */

    function tload(Bytes32SlotType slot) internal view returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            value := tload(slot)
        }
    }

    /**
     * @dev Store `value` at location `slot` in transient storage.
     */
    function tstore(Bytes32SlotType slot, bytes32 value) internal {
        /// @solidity memory-safe-assembly
        assembly {
            tstore(slot, value)
        }
    }
}
          

contracts/implementations/IRandom.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

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

abstract contract IRandom {
    uint256 internal constant ZERO = 0;
    uint256 internal constant ONE = 1;
    uint256 internal constant EIGHT = 8;
    uint256 internal constant ONE_SIX = 16;
    uint256 internal constant THREE_TWO = 32;
    uint256 internal constant FOUR_EIGHT = 48;
    uint256 internal constant NINE_SIX = 96;
    uint256 internal constant ONE_TWO_EIGHT = 128;
    uint256 internal constant ONE_SIX_ZERO = 160;
    uint256 internal constant TWO_ZERO_EIGHT = 208;
    uint256 internal constant TWO_ZERO_NINE = ONE + TWO_ZERO_EIGHT;
    uint256 internal constant TWO_FOUR_EIGHT = 248;
    uint256 internal constant TWO_FIVE_FIVE = 255;
    uint256 internal constant TWO_FIVE_SIX = 256;

    mapping(bytes32 key => uint256 timeline) internal _timeline;
    mapping(bytes32 key => bytes32 seed) internal _seed;

    struct Randomness {
        uint256 timeline;
        bytes32 seed;
    }

    function heat(uint256 required, uint256 expiryOffset, address token, PreimageLocation.Info[] calldata info)
        external
        payable
        virtual
        returns (bytes32);
    function pointer(PreimageLocation.Info calldata info) external view virtual returns (address);
    function consumed(PreimageLocation.Info calldata info) external view virtual returns (bool);
    function randomness(bytes32 key) external view virtual returns (Randomness memory);
    function latest(address account, bool onlySameTx) external view virtual returns (bytes32);

    function expired(uint256 timeline) external view virtual returns (bool) {
        return _expired(timeline);
    }

    function _expired(uint256 timeline) internal view virtual returns (bool) {
        unchecked {
            // end
            return (timeline << (TWO_FIVE_FIVE - EIGHT) >> TWO_FIVE_FIVE == ZERO ? block.number : block.timestamp)
            // start
            - (uint256(uint48(timeline >> FOUR_EIGHT)))
            // expiration delta
            > (uint256(uint40(timeline) >> (EIGHT + ONE)));
        }
    }
}
          

multicaller/src/LibMulticaller.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * @title LibMulticaller
 * @author vectorized.eth
 * @notice Library to read the `msg.sender` of the multicaller with sender contract.
 *
 * @dev Note:
 * The functions in this library do NOT guard against reentrancy.
 * A single transaction can recurse through different Multicallers
 * (e.g. `MulticallerWithSender -> contract -> MulticallerWithSigner -> contract`).
 *
 * Think of these functions like `msg.sender`.
 *
 * If your contract `C` can handle reentrancy safely with plain old `msg.sender`
 * for any `A -> C -> B -> C`, you should be fine substituting `msg.sender` with these functions.
 */
library LibMulticaller {
    /**
     * @dev The address of the multicaller contract.
     */
    address internal constant MULTICALLER = 0x0000000000002Bdbf1Bf3279983603Ec279CC6dF;

    /**
     * @dev The address of the multicaller with sender contract.
     */
    address internal constant MULTICALLER_WITH_SENDER = 0x00000000002Fd5Aeb385D324B580FCa7c83823A0;

    /**
     * @dev The address of the multicaller with signer contract.
     */
    address internal constant MULTICALLER_WITH_SIGNER = 0x000000000000D9ECebf3C23529de49815Dac1c4c;

    /**
     * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`.
     */
    function multicallerSender() internal view returns (address result) {
        return at(MULTICALLER_WITH_SENDER);
    }

    /**
     * @dev Returns the signer of `aggregateWithSigner` on `MULTICALLER_WITH_SIGNER`.
     */
    function multicallerSigner() internal view returns (address result) {
        return at(MULTICALLER_WITH_SIGNER);
    }

    /**
     * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SENDER`.
     *      Otherwise, returns `msg.sender`.
     */
    function sender() internal view returns (address result) {
        return resolve(MULTICALLER_WITH_SENDER);
    }

    /**
     * @dev Returns the caller of `aggregateWithSigner` on `MULTICALLER_WITH_SIGNER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SIGNER`.
     *      Otherwise, returns `msg.sender`.
     */
    function signer() internal view returns (address) {
        return resolve(MULTICALLER_WITH_SIGNER);
    }

    /**
     * @dev Returns the caller or signer at `a`.
     * @param a The multicaller with sender / signer.
     */
    function at(address a) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x00)
            if iszero(staticcall(gas(), a, codesize(), 0x00, 0x00, 0x20)) {
                revert(codesize(), codesize()) // For better gas estimation.
            }
            result := mload(0x00)
        }
    }

    /**
     * @dev Returns the caller or signer at `a`, if the caller is `a`.
     * @param a The multicaller with sender / signer.
     */
    function resolve(address a) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, caller())
            if eq(caller(), a) {
                if iszero(staticcall(gas(), a, codesize(), 0x00, 0x00, 0x20)) {
                    revert(codesize(), codesize()) // For better gas estimation.
                }
            }
            result := mload(0x00)
        }
    }

    /**
     * @dev Returns the caller of `aggregateWithSender` on `MULTICALLER_WITH_SENDER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SENDER`.
     *      Returns the signer of `aggregateWithSigner` on `MULTICALLER_WITH_SIGNER`,
     *      if the current context's `msg.sender` is `MULTICALLER_WITH_SIGNER`.
     *      Otherwise, returns `msg.sender`.
     */
    function senderOrSigner() internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, caller())
            let withSender := MULTICALLER_WITH_SENDER
            if eq(caller(), withSender) {
                if iszero(staticcall(gas(), withSender, codesize(), 0x00, 0x00, 0x20)) {
                    revert(codesize(), codesize()) // For better gas estimation.
                }
            }
            let withSigner := MULTICALLER_WITH_SIGNER
            if eq(caller(), withSigner) {
                if iszero(staticcall(gas(), withSigner, codesize(), 0x00, 0x00, 0x20)) {
                    revert(codesize(), codesize()) // For better gas estimation.
                }
            }
            result := mload(0x00)
        }
    }
}
          

solady/src/utils/EfficientHashLib.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for efficiently performing keccak256 hashes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EfficientHashLib.sol)
/// @dev To avoid stack-too-deep, you can use:
/// ```
/// bytes32[] memory buffer = EfficientHashLib.malloc(10);
/// EfficientHashLib.set(buffer, 0, value0);
/// ..
/// EfficientHashLib.set(buffer, 9, value9);
/// bytes32 finalHash = EfficientHashLib.hash(buffer);
/// ```
library EfficientHashLib {
    /// @dev Returns `keccak256(abi.encode(value0))`.
    function hash(bytes32 value0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0))`.
    function hash(uint256 value0) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            result := keccak256(0x00, 0x20)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1))`.
    function hash(bytes32 value0, bytes32 value1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            mstore(0x20, value1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1))`.
    function hash(uint256 value0, uint256 value1) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, value0)
            mstore(0x20, value1)
            result := keccak256(0x00, 0x40)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2))`.
    function hash(bytes32 value0, bytes32 value1, bytes32 value2)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2))`.
    function hash(uint256 value0, uint256 value1, uint256 value2)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            result := keccak256(m, 0x60)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2, value3))`.
    function hash(bytes32 value0, bytes32 value1, bytes32 value2, bytes32 value3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, value1, value2, value3))`.
    function hash(uint256 value0, uint256 value1, uint256 value2, uint256 value3)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            result := keccak256(m, 0x80)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value4))`.
    function hash(bytes32 value0, bytes32 value1, bytes32 value2, bytes32 value3, bytes32 value4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value4))`.
    function hash(uint256 value0, uint256 value1, uint256 value2, uint256 value3, uint256 value4)
        internal
        pure
        returns (bytes32 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            result := keccak256(m, 0xa0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value5))`.
    function hash(
        bytes32 value0,
        bytes32 value1,
        bytes32 value2,
        bytes32 value3,
        bytes32 value4,
        bytes32 value5
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value5))`.
    function hash(
        uint256 value0,
        uint256 value1,
        uint256 value2,
        uint256 value3,
        uint256 value4,
        uint256 value5
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            result := keccak256(m, 0xc0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value6))`.
    function hash(
        bytes32 value0,
        bytes32 value1,
        bytes32 value2,
        bytes32 value3,
        bytes32 value4,
        bytes32 value5,
        bytes32 value6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value6))`.
    function hash(
        uint256 value0,
        uint256 value1,
        uint256 value2,
        uint256 value3,
        uint256 value4,
        uint256 value5,
        uint256 value6
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            result := keccak256(m, 0xe0)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value7))`.
    function hash(
        bytes32 value0,
        bytes32 value1,
        bytes32 value2,
        bytes32 value3,
        bytes32 value4,
        bytes32 value5,
        bytes32 value6,
        bytes32 value7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            mstore(add(m, 0xe0), value7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(value0, .., value7))`.
    function hash(
        uint256 value0,
        uint256 value1,
        uint256 value2,
        uint256 value3,
        uint256 value4,
        uint256 value5,
        uint256 value6,
        uint256 value7
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, value0)
            mstore(add(m, 0x20), value1)
            mstore(add(m, 0x40), value2)
            mstore(add(m, 0x60), value3)
            mstore(add(m, 0x80), value4)
            mstore(add(m, 0xa0), value5)
            mstore(add(m, 0xc0), value6)
            mstore(add(m, 0xe0), value7)
            result := keccak256(m, 0x100)
        }
    }

    /// @dev Returns `keccak256(abi.encode(buffer[0], .., value[buffer.length - 1]))`.
    function hash(bytes32[] memory buffer) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(add(buffer, 0x20), shl(5, mload(buffer)))
        }
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, bytes32 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Sets `buffer[i]` to `value`, without a bounds check.
    /// Returns the `buffer` for function chaining.
    function set(bytes32[] memory buffer, uint256 i, uint256 value)
        internal
        pure
        returns (bytes32[] memory)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(add(buffer, shl(5, add(1, i))), value)
        }
        return buffer;
    }

    /// @dev Returns `new bytes32[](n)`, without zeroing out the memory.
    function malloc(uint256 n) internal pure returns (bytes32[] memory buffer) {
        /// @solidity memory-safe-assembly
        assembly {
            buffer := mload(0x40)
            mstore(buffer, n)
            mstore(0x40, add(shl(5, add(1, n)), buffer))
        }
    }

    /// @dev Frees memory that has been allocated for `buffer`.
    /// No-op if `buffer.length` is zero, or if new memory has been allocated after `buffer`.
    function free(bytes32[] memory buffer) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(buffer)
            mstore(shl(6, lt(iszero(n), eq(add(shl(5, add(1, n)), buffer), mload(0x40)))), buffer)
        }
    }
}
          

solady/src/utils/LibPRNG.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for generating pseudorandom numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibPRNG.sol)
/// @author LazyShuffler based on NextShuffler by aschlosberg (divergencearran)
/// (https://github.com/divergencetech/ethier/blob/main/contracts/random/NextShuffler.sol)
library LibPRNG {
    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev The initial length must be greater than zero and less than `2**32 - 1`.
    error InvalidInitialLazyShufflerLength();

    /// @dev The new length must not be less than the current length.
    error InvalidNewLazyShufflerLength();

    /// @dev The lazy shuffler has not been initialized.
    error LazyShufflerNotInitialized();

    /// @dev Cannot double initialize the lazy shuffler.
    error LazyShufflerAlreadyInitialized();

    /// @dev The lazy shuffle has finished.
    error LazyShuffleFinished();

    /// @dev The queried index is out of bounds.
    error LazyShufflerGetOutOfBounds();

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant WAD = 1e18;

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev A pseudorandom number state in memory.
    struct PRNG {
        uint256 state;
    }

    /// @dev A lazy Fisher-Yates shuffler for a range `[0..n)` in storage.
    struct LazyShuffler {
        // Bits Layout:
        // - [0..31]    `numShuffled`
        // - [32..223]  `permutationSlot`
        // - [224..255] `length`
        uint256 _state;
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                         OPERATIONS                         */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Seeds the `prng` with `state`.
    function seed(PRNG memory prng, uint256 state) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(prng, state)
        }
    }

    /// @dev Returns the next pseudorandom uint256.
    /// All bits of the returned uint256 pass the NIST Statistical Test Suite.
    function next(PRNG memory prng) internal pure returns (uint256 result) {
        // We simply use `keccak256` for a great balance between
        // runtime gas costs, bytecode size, and statistical properties.
        //
        // A high-quality LCG with a 32-byte state
        // is only about 30% more gas efficient during runtime,
        // but requires a 32-byte multiplier, which can cause bytecode bloat
        // when this function is inlined.
        //
        // Using this method is about 2x more efficient than
        // `nextRandomness = uint256(keccak256(abi.encode(randomness)))`.
        /// @solidity memory-safe-assembly
        assembly {
            result := keccak256(prng, 0x20)
            mstore(prng, result)
        }
    }

    /// @dev Returns a pseudorandom uint256, uniformly distributed
    /// between 0 (inclusive) and `upper` (exclusive).
    /// If your modulus is big, this method is recommended
    /// for uniform sampling to avoid modulo bias.
    /// For uniform sampling across all uint256 values,
    /// or for small enough moduli such that the bias is negligible,
    /// use {next} instead.
    function uniform(PRNG memory prng, uint256 upper) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := keccak256(prng, 0x20)
                mstore(prng, result)
                if iszero(lt(result, mod(sub(0, upper), upper))) { break }
            }
            result := mod(result, upper)
        }
    }

    /// @dev Returns a sample from the standard normal distribution denominated in `WAD`.
    function standardNormalWad(PRNG memory prng) internal pure returns (int256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Technically, this is the Irwin-Hall distribution with 20 samples.
            // The chance of drawing a sample outside 10 σ from the standard normal distribution
            // is ā‰ˆ 0.000000000000000000000015, which is insignificant for most practical purposes.
            // Passes the Kolmogorov-Smirnov test for 200k samples. Uses about 322 gas.
            result := keccak256(prng, 0x20)
            mstore(prng, result)
            let n := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43 // Prime.
            let a := 0x100000000000000000000000000000051 // Prime and a primitive root of `n`.
            let m := 0x1fffffffffffffff1fffffffffffffff1fffffffffffffff1fffffffffffffff
            let s := 0x1000000000000000100000000000000010000000000000001
            let r1 := mulmod(result, a, n)
            let r2 := mulmod(r1, a, n)
            let r3 := mulmod(r2, a, n)
            // forgefmt: disable-next-item
            result := sub(sar(96, mul(26614938895861601847173011183,
                add(add(shr(192, mul(s, add(and(m, result), and(m, r1)))),
                shr(192, mul(s, add(and(m, r2), and(m, r3))))),
                shr(192, mul(s, and(m, mulmod(r3, a, n))))))), 7745966692414833770)
        }
    }

    /// @dev Returns a sample from the unit exponential distribution denominated in `WAD`.
    function exponentialWad(PRNG memory prng) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Passes the Kolmogorov-Smirnov test for 200k samples.
            // Gas usage varies, starting from about 172+ gas.
            let r := keccak256(prng, 0x20)
            mstore(prng, r)
            let p := shl(129, r)
            let w := shl(1, r)
            if iszero(gt(w, p)) {
                let n := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43 // Prime.
                let a := 0x100000000000000000000000000000051 // Prime and a primitive root of `n`.
                for {} 1 {} {
                    r := mulmod(r, a, n)
                    if iszero(lt(shl(129, r), w)) {
                        r := mulmod(r, a, n)
                        result := add(1000000000000000000, result)
                        w := shl(1, r)
                        p := shl(129, r)
                        if iszero(lt(w, p)) { break }
                        continue
                    }
                    w := shl(1, r)
                    if iszero(lt(w, shl(129, r))) { break }
                }
            }
            result := add(div(p, shl(129, 170141183460469231732)), result)
        }
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*             MEMORY ARRAY SHUFFLING OPERATIONS              */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Shuffles the array in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a)
            let w := not(0)
            let mask := shr(128, w)
            if n {
                for { a := add(a, 0x20) } 1 {} {
                    // We can just directly use `keccak256`, cuz
                    // the other approaches don't save much.
                    let r := keccak256(prng, 0x20)
                    mstore(prng, r)

                    // Note that there will be a very tiny modulo bias
                    // if the length of the array is not a power of 2.
                    // For all practical purposes, it is negligible
                    // and will not be a fairness or security concern.
                    {
                        let j := add(a, shl(5, mod(shr(128, r), n)))
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let i := add(a, shl(5, n))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                    }

                    {
                        let j := add(a, shl(5, mod(and(r, mask), n)))
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let i := add(a, shl(5, n))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                    }
                }
            }
        }
    }

    /// @dev Shuffles the array in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, int256[] memory a) internal pure {
        shuffle(prng, _toUints(a));
    }

    /// @dev Shuffles the array in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, address[] memory a) internal pure {
        shuffle(prng, _toUints(a));
    }

    /// @dev Partially shuffles the array in-place with Fisher-Yates shuffle.
    /// The first `k` elements will be uniformly sampled without replacement.
    function shuffle(PRNG memory prng, uint256[] memory a, uint256 k) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a)
            k := xor(k, mul(xor(k, n), lt(n, k))) // `min(n, k)`.
            if k {
                let mask := shr(128, not(0))
                let b := 0
                for { a := add(a, 0x20) } 1 {} {
                    // We can just directly use `keccak256`, cuz
                    // the other approaches don't save much.
                    let r := keccak256(prng, 0x20)
                    mstore(prng, r)

                    // Note that there will be a very tiny modulo bias
                    // if the length of the array is not a power of 2.
                    // For all practical purposes, it is negligible
                    // and will not be a fairness or security concern.
                    {
                        let j := add(a, shl(5, add(b, mod(shr(128, r), sub(n, b)))))
                        let i := add(a, shl(5, b))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                        b := add(b, 1)
                        if eq(b, k) { break }
                    }

                    {
                        let j := add(a, shl(5, add(b, mod(and(r, mask), sub(n, b)))))
                        let i := add(a, shl(5, b))
                        let t := mload(i)
                        mstore(i, mload(j))
                        mstore(j, t)
                        b := add(b, 1)
                        if eq(b, k) { break }
                    }
                }
            }
        }
    }

    /// @dev Partially shuffles the array in-place with Fisher-Yates shuffle.
    /// The first `k` elements will be uniformly sampled without replacement.
    function shuffle(PRNG memory prng, int256[] memory a, uint256 k) internal pure {
        shuffle(prng, _toUints(a), k);
    }

    /// @dev Partially shuffles the array in-place with Fisher-Yates shuffle.
    /// The first `k` elements will be uniformly sampled without replacement.
    function shuffle(PRNG memory prng, address[] memory a, uint256 k) internal pure {
        shuffle(prng, _toUints(a), k);
    }

    /// @dev Shuffles the bytes in-place with Fisher-Yates shuffle.
    function shuffle(PRNG memory prng, bytes memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a)
            let w := not(0)
            let mask := shr(128, w)
            if n {
                let b := add(a, 0x01)
                for { a := add(a, 0x20) } 1 {} {
                    // We can just directly use `keccak256`, cuz
                    // the other approaches don't save much.
                    let r := keccak256(prng, 0x20)
                    mstore(prng, r)

                    // Note that there will be a very tiny modulo bias
                    // if the length of the array is not a power of 2.
                    // For all practical purposes, it is negligible
                    // and will not be a fairness or security concern.
                    {
                        let o := mod(shr(128, r), n)
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let t := mload(add(b, n))
                        mstore8(add(a, n), mload(add(b, o)))
                        mstore8(add(a, o), t)
                    }

                    {
                        let o := mod(and(r, mask), n)
                        n := add(n, w) // `sub(n, 1)`.
                        if iszero(n) { break }

                        let t := mload(add(b, n))
                        mstore8(add(a, n), mload(add(b, o)))
                        mstore8(add(a, o), t)
                    }
                }
            }
        }
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*       STORAGE-BASED RANGE LAZY SHUFFLING OPERATIONS        */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Initializes the state for lazy-shuffling the range `[0..n)`.
    /// Reverts if `n == 0 || n >= 2**32 - 1`.
    /// Reverts if `$` has already been initialized.
    /// If you need to reduce the length after initialization, just use a fresh new `$`.
    function initialize(LazyShuffler storage $, uint256 n) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(sub(n, 1), 0xfffffffe)) {
                mstore(0x00, 0x83b53941) // `InvalidInitialLazyShufflerLength()`.
                revert(0x1c, 0x04)
            }
            if sload($.slot) {
                mstore(0x00, 0x0c9f11f2) // `LazyShufflerAlreadyInitialized()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, $.slot)
            sstore($.slot, or(shl(224, n), shl(32, shr(64, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Increases the length of `$`.
    /// Reverts if `$` has not been initialized.
    function grow(LazyShuffler storage $, uint256 n) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot) // The packed value at `$`.
            // If the new length is smaller than the old length, revert.
            if lt(n, shr(224, state)) {
                mstore(0x00, 0xbed37c6e) // `InvalidNewLazyShufflerLength()`.
                revert(0x1c, 0x04)
            }
            if iszero(state) {
                mstore(0x00, 0x1ead2566) // `LazyShufflerNotInitialized()`.
                revert(0x1c, 0x04)
            }
            sstore($.slot, or(shl(224, n), shr(32, shl(32, state))))
        }
    }

    /// @dev Restarts the shuffler by setting `numShuffled` to zero,
    /// such that all elements can be drawn again.
    /// Restarting does NOT clear the internal permutation, nor changes the length.
    /// Even with the same sequence of randomness, reshuffling can yield different results.
    function restart(LazyShuffler storage $) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot)
            if iszero(state) {
                mstore(0x00, 0x1ead2566) // `LazyShufflerNotInitialized()`.
                revert(0x1c, 0x04)
            }
            sstore($.slot, shl(32, shr(32, state)))
        }
    }

    /// @dev Returns the number of elements that have been shuffled.
    function numShuffled(LazyShuffler storage $) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := and(0xffffffff, sload($.slot))
        }
    }

    /// @dev Returns the length of `$`.
    /// Returns zero if `$` is not initialized, else a non-zero value less than `2**32 - 1`.
    function length(LazyShuffler storage $) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := shr(224, sload($.slot))
        }
    }

    /// @dev Returns if `$` has been initialized.
    function initialized(LazyShuffler storage $) internal view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(iszero(sload($.slot)))
        }
    }

    /// @dev Returns if there are any more elements left to shuffle.
    /// Reverts if `$` is not initialized.
    function finished(LazyShuffler storage $) internal view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot) // The packed value at `$`.
            if iszero(state) {
                mstore(0x00, 0x1ead2566) // `LazyShufflerNotInitialized()`.
                revert(0x1c, 0x04)
            }
            result := eq(shr(224, state), and(0xffffffff, state))
        }
    }

    /// @dev Returns the current value stored at `index`, accounting for all historical shuffling.
    /// Reverts if `index` is greater than or equal to the `length` of `$`.
    function get(LazyShuffler storage $, uint256 index) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let state := sload($.slot) // The packed value at `$`.
            let n := shr(224, state) // Length of `$`.
            if iszero(lt(index, n)) {
                mstore(0x00, 0x61367cc4) // `LazyShufflerGetOutOfBounds()`.
                revert(0x1c, 0x04)
            }
            let u32 := gt(n, 0xfffe)
            let s := add(shr(sub(4, u32), index), shr(64, shl(32, state))) // Bucket slot.
            let o := shl(add(4, u32), and(index, shr(u32, 15))) // Bucket slot offset (bits).
            let m := sub(shl(shl(u32, 16), 1), 1) // Value mask.
            result := and(m, shr(o, sload(s)))
            result := xor(index, mul(xor(index, sub(result, 1)), iszero(iszero(result))))
        }
    }

    /// @dev Does a single Fisher-Yates shuffle step, increments the `numShuffled` in `$`,
    /// and returns the next value in the shuffled range.
    /// `randomness` can be taken from a good-enough source, or a higher quality source like VRF.
    /// Reverts if there are no more values to shuffle, which includes the case if `$` is not initialized.
    function next(LazyShuffler storage $, uint256 randomness) internal returns (uint256 chosen) {
        /// @solidity memory-safe-assembly
        assembly {
            function _get(u32_, state_, i_) -> _value {
                let s_ := add(shr(sub(4, u32_), i_), shr(64, shl(32, state_))) // Bucket slot.
                let o_ := shl(add(4, u32_), and(i_, shr(u32_, 15))) // Bucket slot offset (bits).
                let m_ := sub(shl(shl(u32_, 16), 1), 1) // Value mask.
                _value := and(m_, shr(o_, sload(s_)))
                _value := xor(i_, mul(xor(i_, sub(_value, 1)), iszero(iszero(_value))))
            }
            function _set(u32_, state_, i_, value_) {
                let s_ := add(shr(sub(4, u32_), i_), shr(64, shl(32, state_))) // Bucket slot.
                let o_ := shl(add(4, u32_), and(i_, shr(u32_, 15))) // Bucket slot offset (bits).
                let m_ := sub(shl(shl(u32_, 16), 1), 1) // Value mask.
                let v_ := sload(s_) // Bucket slot value.
                value_ := mul(iszero(eq(i_, value_)), add(value_, 1))
                sstore(s_, xor(v_, shl(o_, and(m_, xor(shr(o_, v_), value_)))))
            }
            let state := sload($.slot) // The packed value at `$`.
            let shuffled := and(0xffffffff, state) // Number of elements shuffled.
            let n := shr(224, state) // Length of `$`.
            let remainder := sub(n, shuffled) // Number of elements left to shuffle.
            if iszero(remainder) {
                mstore(0x00, 0x51065f79) // `LazyShuffleFinished()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, randomness) // (Re)hash the randomness so that we don't
            mstore(0x20, shuffled) // need to expect guarantees on its distribution.
            let index := add(mod(keccak256(0x00, 0x40), remainder), shuffled)
            chosen := _get(gt(n, 0xfffe), state, index)
            _set(gt(n, 0xfffe), state, index, _get(gt(n, 0xfffe), state, shuffled))
            _set(gt(n, 0xfffe), state, shuffled, chosen)
            sstore($.slot, add(1, state)) // Increment the `numShuffled` by 1, and store it.
        }
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            // As any address written to memory will have the upper 96 bits
            // of the word zeroized (as per Solidity spec), we can directly
            // compare these addresses as if they are whole uint256 words.
            casted := a
        }
    }
}
          

solady/src/utils/SSTORE2.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
/// @author Modified from SSTORE3 (https://github.com/Philogy/sstore3)
library SSTORE2 {
    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev The proxy initialization code.
    uint256 private constant _CREATE3_PROXY_INITCODE = 0x67363d3d37363d34f03d5260086018f3;

    /// @dev Hash of the `_CREATE3_PROXY_INITCODE`.
    /// Equivalent to `keccak256(abi.encodePacked(hex"67363d3d37363d34f03d5260086018f3"))`.
    bytes32 internal constant CREATE3_PROXY_INITCODE_HASH =
        0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f;

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Unable to deploy the storage contract.
    error DeploymentFailed();

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                         WRITE LOGIC                        */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    function write(bytes memory data) internal returns (address pointer) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data) // Let `l` be `n + 1`. +1 as we prefix a STOP opcode.
            /**
             * ---------------------------------------------------+
             * Opcode | Mnemonic       | Stack     | Memory       |
             * ---------------------------------------------------|
             * 61 l   | PUSH2 l        | l         |              |
             * 80     | DUP1           | l l       |              |
             * 60 0xa | PUSH1 0xa      | 0xa l l   |              |
             * 3D     | RETURNDATASIZE | 0 0xa l l |              |
             * 39     | CODECOPY       | l         | [0..l): code |
             * 3D     | RETURNDATASIZE | 0 l       | [0..l): code |
             * F3     | RETURN         |           | [0..l): code |
             * 00     | STOP           |           |              |
             * ---------------------------------------------------+
             * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
             * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
             */
            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n)))
            // Deploy a new contract with the generated creation code.
            pointer := create(0, add(data, 0x15), add(n, 0xb))
            if iszero(pointer) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /// @dev Writes `data` into the bytecode of a storage contract with `salt`
    /// and returns its normal CREATE2 deterministic address.
    function writeCounterfactual(bytes memory data, bytes32 salt)
        internal
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data)
            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n)))
            // Deploy a new contract with the generated creation code.
            pointer := create2(0, add(data, 0x15), add(n, 0xb), salt)
            if iszero(pointer) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    /// This uses the so-called "CREATE3" workflow,
    /// which means that `pointer` is agnostic to `data, and only depends on `salt`.
    function writeDeterministic(bytes memory data, bytes32 salt)
        internal
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data)
            mstore(0x00, _CREATE3_PROXY_INITCODE) // Store the `_PROXY_INITCODE`.
            let proxy := create2(0, 0x10, 0x10, salt)
            if iszero(proxy) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, proxy) // Store the proxy's address.
            // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
            // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
            mstore(0x00, 0xd694)
            mstore8(0x34, 0x01) // Nonce of the proxy contract (1).
            pointer := keccak256(0x1e, 0x17)

            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            mstore(add(data, gt(n, 0xfffe)), add(0xfe61000180600a3d393df300, shl(0x40, n)))
            if iszero(
                mul( // The arguments of `mul` are evaluated last to first.
                    extcodesize(pointer),
                    call(gas(), proxy, 0, add(data, 0x15), add(n, 0xb), codesize(), 0x00)
                )
            ) {
                mstore(0x00, 0x30116425) // `DeploymentFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                    ADDRESS CALCULATIONS                    */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Returns the initialization code hash of the storage contract for `data`.
    /// Used for mining vanity addresses with create2crunch.
    function initCodeHash(bytes memory data) internal pure returns (bytes32 hash) {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(data)
            // Do a out-of-gas revert if `n + 1` is more than 2 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0xfffe))
            mstore(data, add(0x61000180600a3d393df300, shl(0x40, n)))
            hash := keccak256(add(data, 0x15), add(n, 0xb))
            mstore(data, n) // Restore the length of `data`.
        }
    }

    /// @dev Equivalent to `predictCounterfactualAddress(data, salt, address(this))`
    function predictCounterfactualAddress(bytes memory data, bytes32 salt)
        internal
        view
        returns (address pointer)
    {
        pointer = predictCounterfactualAddress(data, salt, address(this));
    }

    /// @dev Returns the CREATE2 address of the storage contract for `data`
    /// deployed with `salt` by `deployer`.
    /// Note: The returned result has dirty upper 96 bits. Please clean if used in assembly.
    function predictCounterfactualAddress(bytes memory data, bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = initCodeHash(data);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, hash)
            mstore(0x01, shl(96, deployer))
            mstore(0x15, salt)
            predicted := keccak256(0x00, 0x55)
            // Restore the part of the free memory pointer that has been overwritten.
            mstore(0x35, 0)
        }
    }

    /// @dev Equivalent to `predictDeterministicAddress(salt, address(this))`.
    function predictDeterministicAddress(bytes32 salt) internal view returns (address pointer) {
        pointer = predictDeterministicAddress(salt, address(this));
    }

    /// @dev Returns the "CREATE3" deterministic address for `salt` with `deployer`.
    function predictDeterministicAddress(bytes32 salt, address deployer)
        internal
        pure
        returns (address pointer)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, deployer) // Store `deployer`.
            mstore8(0x0b, 0xff) // Store the prefix.
            mstore(0x20, salt) // Store the salt.
            mstore(0x40, CREATE3_PROXY_INITCODE_HASH) // Store the bytecode hash.

            mstore(0x14, keccak256(0x0b, 0x55)) // Store the proxy's address.
            mstore(0x40, m) // Restore the free memory pointer.
            // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
            // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
            mstore(0x00, 0xd694)
            mstore8(0x34, 0x01) // Nonce of the proxy contract (1).
            pointer := keccak256(0x1e, 0x17)
        }
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                         READ LOGIC                         */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Equivalent to `read(pointer, 0, 2 ** 256 - 1)`.
    function read(address pointer) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            data := mload(0x40)
            let n := and(sub(extcodesize(pointer), 0x01), 0xffffffffff)
            extcodecopy(pointer, add(data, 0x1f), 0x00, add(n, 0x21))
            mstore(data, n) // Store the length.
            mstore(0x40, add(n, add(data, 0x40))) // Allocate memory.
        }
    }

    /// @dev Equivalent to `read(pointer, start, 2 ** 256 - 1)`.
    function read(address pointer, uint256 start) internal view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            data := mload(0x40)
            let n := and(sub(extcodesize(pointer), 0x01), 0xffffffffff)
            extcodecopy(pointer, add(data, 0x1f), start, add(n, 0x21))
            mstore(data, mul(sub(n, start), lt(start, n))) // Store the length.
            mstore(0x40, add(data, add(0x40, mload(data)))) // Allocate memory.
        }
    }

    /// @dev Returns the a slice of the data on `pointer` from `start` to `end`.
    /// `start` and `end` will be clamped to the range `[0, args.length]`.
    /// The `pointer` MUST be deployed via the SSTORE2 write functions.
    /// Otherwise, the behavior is undefined.
    /// Out-of-gas reverts if `pointer` does not have any code.
    function read(address pointer, uint256 start, uint256 end)
        internal
        view
        returns (bytes memory data)
    {
        /// @solidity memory-safe-assembly
        assembly {
            data := mload(0x40)
            let d := and(0xffff, sub(end, start))
            extcodecopy(pointer, add(data, 0x1f), start, add(d, 0x01))
            if iszero(and(0xff, mload(add(data, d)))) {
                let n := sub(extcodesize(pointer), 0x01)
                returndatacopy(returndatasize(), returndatasize(), shr(64, n))
                d := mul(gt(n, start), sub(d, mul(gt(end, n), sub(end, n))))
            }
            mstore(data, mul(d, lt(start, end))) // Store the length.
            mstore(add(add(data, 0x20), d), 0) // Zeroize the slot after the bytes.
            mstore(0x40, add(add(data, 0x40), d)) // Allocate memory.
        }
    }
}
          

solady/src/utils/SafeTransferLib.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*Ā“:°•.°+.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°•.*•“.*:˚.°*.Ėšā€¢Ā“.°:°•.°+.*•“.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.Ā“+˚.*°.˚:*.“•*.+°.•°:Ā“*.“•*.•°.•°:°.Ā“:ā€¢ĖšĀ°.*°.˚:*.Ā“+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success :=
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `1` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}
          

Compiler Settings

{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":false},"libraries":{},"evmVersion":"cancun"}
              

Contract ABI

[{"type":"error","name":"Misconfigured","inputs":[]},{"type":"error","name":"MissingPayment","inputs":[]},{"type":"error","name":"NotInCohort","inputs":[]},{"type":"error","name":"SecretMismatch","inputs":[]},{"type":"error","name":"SignerMismatch","inputs":[]},{"type":"error","name":"UnableToService","inputs":[]},{"type":"event","name":"Bleach","inputs":[{"type":"address","name":"provider","internalType":"address","indexed":true},{"type":"bytes32","name":"section","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Cast","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"seed","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Chop","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Expired","inputs":[{"type":"address","name":"recipient","internalType":"address","indexed":true},{"type":"address","name":"ender","internalType":"address","indexed":true},{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Heat","inputs":[{"type":"address","name":"provider","internalType":"address","indexed":true},{"type":"bytes32","name":"section","internalType":"bytes32","indexed":false},{"type":"uint256","name":"index","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Ink","inputs":[{"type":"address","name":"provider","internalType":"address","indexed":true},{"type":"uint256","name":"offset","internalType":"uint256","indexed":false},{"type":"address","name":"pointer","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Reveal","inputs":[{"type":"address","name":"provider","internalType":"address","indexed":true},{"type":"bytes32","name":"location","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"formerSecret","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"Start","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"bytes32","name":"key","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"bleach","inputs":[{"type":"tuple","name":"info","internalType":"struct PreimageLocation.Info","components":[{"type":"address","name":"provider","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"}]}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cast","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"},{"type":"tuple[]","name":"preimageInfo","internalType":"struct PreimageLocation.Info[]","components":[{"type":"address","name":"provider","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"bytes32[]","name":"revealed","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"chop","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"},{"type":"tuple[]","name":"preimageInfo","internalType":"struct PreimageLocation.Info[]","components":[{"type":"address","name":"provider","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"consumed","inputs":[{"type":"tuple","name":"nfo","internalType":"struct PreimageLocation.Info","components":[{"type":"address","name":"provider","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"expired","inputs":[{"type":"uint256","name":"timeline","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"handoff","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"int256","name":"amount","internalType":"int256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"heat","inputs":[{"type":"uint256","name":"required","internalType":"uint256"},{"type":"uint256","name":"expiryOffset","internalType":"uint256"},{"type":"address","name":"token","internalType":"address"},{"type":"tuple[]","name":"potentialLocations","internalType":"struct PreimageLocation.Info[]","components":[{"type":"address","name":"provider","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"}]}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"ink","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"key","internalType":"bytes32"}],"name":"latest","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"bool","name":"onlySameTx","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pointer","inputs":[{"type":"tuple","name":"info","internalType":"struct PreimageLocation.Info","components":[{"type":"address","name":"provider","internalType":"address"},{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"offset","internalType":"uint256"},{"type":"uint256","name":"index","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IRandom.Randomness","components":[{"type":"uint256","name":"timeline","internalType":"uint256"},{"type":"bytes32","name":"seed","internalType":"bytes32"}]}],"name":"randomness","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"}]}]
              

Contract Creation Code

0x608060405234601c57600e6020565b61348961002b823961348990f35b6026565b60405190565b5f80fdfe60806040526004361015610013575b610914565b61001d5f356100dc565b806302a381bf146100d757806307bbadd7146100d25780630cf9dff7146100cd5780631ff3434f146100c85780635312f336146100c357806358e5abde146100be57806362fd0d1f146100b95780638492c30b146100b4578063870c096a146100af578063ba065e1f146100aa578063c464e628146100a55763f7888aec0361000e576108de565b610866565b61073e565b6106eb565b610693565b610616565b610556565b610487565b61040c565b6103a2565b6102fb565b61018f565b60e01c90565b60405190565b5f80fd5b5f80fd5b60018060a01b031690565b610104906100f0565b90565b610110816100fb565b0361011757565b5f80fd5b9050359061012882610107565b565b90565b6101368161012a565b0361013d57565b5f80fd5b9050359061014e8261012d565b565b90916060828403126101855761018261016b845f850161011b565b93610179816020860161011b565b93604001610141565b90565b6100e8565b5f0190565b6101a361019d366004610150565b91610a7d565b6101ab6100e2565b806101b58161018a565b0390f35b90565b6101c5816101b9565b036101cc57565b5f80fd5b905035906101dd826101bc565b565b5f80fd5b5f80fd5b5f80fd5b909182601f830112156102255781359167ffffffffffffffff8311610220576020019260a0830284011161021b57565b6101e7565b6101e3565b6101df565b909182601f830112156102645781359167ffffffffffffffff831161025f57602001926020830284011161025a57565b6101e7565b6101e3565b6101df565b6060818303126102cf5761027f825f83016101d0565b92602082013567ffffffffffffffff81116102ca57836102a09184016101eb565b929093604082013567ffffffffffffffff81116102c5576102c1920161022a565b9091565b6100ec565b6100ec565b6100e8565b151590565b6102e2906102d4565b9052565b91906102f9905f602085019401906102d9565b565b61032661031561030c366004610269565b93929092610bf3565b61031d6100e2565b918291826102e6565b0390f35b5f80fd5b9060208282031261034757610344915f016101d0565b90565b6100e8565b90565b6103589061034c565b9052565b610365906101b9565b9052565b9060208061038b936103815f8201515f86019061034f565b015191019061035c565b565b91906103a0905f60408501940190610369565b565b346103d2576103ce6103bd6103b836600461032e565b610d19565b6103c56100e2565b9182918261038d565b0390f35b61032a565b5f80fd5b908160a09103126103e95790565b6103d7565b9060a08282031261040757610404915f016103db565b90565b6100e8565b3461043c576104386104276104223660046103ee565b610d79565b61042f6100e2565b918291826102e6565b0390f35b61032a565b9190916040818403126104825761045a835f83016101d0565b92602082013567ffffffffffffffff811161047d5761047992016101eb565b9091565b6100ec565b6100e8565b61049b610495366004610441565b91610e7f565b6104a36100e2565b806104ad8161018a565b0390f35b6104ba8161034c565b036104c157565b5f80fd5b905035906104d2826104b1565b565b9060808282031261052f576104eb815f84016104c5565b926104f982602085016104c5565b92610507836040830161011b565b92606082013567ffffffffffffffff811161052a5761052692016101eb565b9091565b6100ec565b6100e8565b61053d906101b9565b9052565b9190610554905f60208501940190610534565b565b6105816105706105673660046104d4565b939290926111e0565b6105786100e2565b91829182610541565b0390f35b909182601f830112156105bf5781359167ffffffffffffffff83116105ba5760200192600183028401116105b557565b6101e7565b6101e3565b6101df565b91606083830312610611576105db825f850161011b565b926105e983602083016104c5565b92604082013567ffffffffffffffff811161060c576106089201610585565b9091565b6100ec565b6100e8565b61062d6106243660046105c4565b929190916117d7565b6106356100e2565b8061063f8161018a565b0390f35b61064c816102d4565b0361065357565b5f80fd5b9050359061066482610643565b565b919060408382031261068e578061068261068b925f860161011b565b93602001610657565b90565b6100e8565b346106c4576106c06106af6106a9366004610666565b9061199a565b6106b76100e2565b91829182610541565b0390f35b61032a565b6106d2906100fb565b9052565b91906106e9905f602085019401906106c9565b565b3461071b576107176107066107013660046103ee565b611a73565b61070e6100e2565b918291826106d6565b0390f35b61032a565b9060208282031261073957610736915f016104c5565b90565b6100e8565b3461076e5761076a610759610754366004610720565b611add565b6107616100e2565b918291826102e6565b0390f35b61032a565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061079f90610777565b810190811067ffffffffffffffff8211176107b957604052565b610781565b906107d16107ca6100e2565b9283610795565b565b919060a0838203126108435761083c906107ed60a06107be565b936107fa825f830161011b565b5f86015261080b826020830161011b565b602086015261081d82604083016104c5565b604086015261082f82606083016104c5565b60608601526080016104c5565b6080830152565b610773565b9060a0828203126108615761085e915f016107d3565b90565b6100e8565b610879610874366004610848565b611aff565b6108816100e2565b8061088b8161018a565b0390f35b91906040838203126108b757806108ab6108b4925f860161011b565b9360200161011b565b90565b6100e8565b6108c59061034c565b9052565b91906108dc905f602085019401906108bc565b565b3461090f5761090b6108fa6108f436600461088f565b90611c2b565b6109026100e2565b918291826108c9565b0390f35b61032a565b5f80fd5b90565b90565b61093261092d61093792610918565b61091b565b6100f0565b90565b6109439061091e565b90565b61095a61095561095f92610918565b61091b565b61012a565b90565b61097661097161097b9261012a565b61091b565b61034c565b90565b610989905f0361012a565b90565b6109a061099b6109a5926100f0565b61091b565b6100f0565b90565b6109b19061098c565b90565b6109bd906109a8565b90565b906109ca906109b4565b5f5260205260405f2090565b906109e0906109b4565b5f5260205260405f2090565b5f1c90565b90565b610a00610a05916109ec565b6109f1565b90565b610a1290546109f4565b90565b90610a20910161034c565b90565b5f1b90565b90610a345f1991610a23565b9181191691161790565b610a52610a4d610a579261034c565b61091b565b61034c565b90565b90565b90610a72610a6d610a7992610a3e565b610a5a565b8254610a28565b9055565b9091610a87611c53565b9180610aa3610a9d610a985f61093a565b6100fb565b916100fb565b145f14610b405750815b9181610ac1610abb5f610946565b9161012a565b125f14610b1857610b1593610afb610af3610b0f94610b009490610aed610ae8869261097e565b610962565b91611de9565b9460036109c0565b6109d6565b91610b0a83610a08565b610a15565b90610a5d565b5b565b9091610b3b93610b359193610b2f82949291610962565b91611cd3565b91611d75565b610b16565b610aad565b5f90565b610b5d610b58610b6292610918565b61091b565b61034c565b90565b610b6e5f610b49565b90565b67ffffffffffffffff8111610b895760208091020190565b610781565b90929192610ba3610b9e82610b71565b6107be565b9381855260208086019202830192818411610be057915b838310610bc75750505050565b60208091610bd584866101d0565b815201920191610bba565b6101e7565b610bf0913691610b8e565b90565b610c3694610c309194939294610c07610b45565b5034610c22610c1c610c17610b65565b61034c565b9161034c565b11610c39575b949293610be5565b92611f4f565b90565b610c49610c44611c53565b611ea0565b610c28565b610c5860406107be565b90565b5f90565b5f90565b610c6b610c4e565b9060208083610c78610c5b565b815201610c83610c5f565b81525050565b610c91610c63565b90565b610c9d906101b9565b90565b90610caa90610c94565b5f5260205260405f2090565b90610cc090610c94565b5f5260205260405f2090565b90565b610cdb610ce0916109ec565b610ccc565b90565b610ced9054610ccf565b90565b610cfa60406107be565b90565b90610d079061034c565b9052565b90610d15906101b9565b9052565b610d21610c89565b50610d68610d4b610d46610d3e610d395f8690610ca0565b610a08565b936001610cb6565b610ce3565b610d5f610d56610cf0565b935f8501610cfd565b60208301610d0b565b90565b610d769036906107d3565b90565b610d8e610d9391610d88610b45565b50610d6b565b612364565b90565b90565b610dad610da8610db292610d96565b61091b565b61034c565b90565b610dbf6060610d99565b90565b1c90565b610de590610ddf610dd9610dea9461034c565b9161034c565b90610dc2565b61034c565b90565b610e01610dfc610e069261034c565b61091b565b6100f0565b90565b610e1d610e18610e229261034c565b610a23565b6101b9565b90565b5f90565b5090565b634e487b7160e01b5f52603260045260245ffd5b9190811015610e515760a0020190565b610e2d565b35610e60816104b1565b90565b6001610e6f910161034c565b90565b35610e7c81610107565b90565b929190610e8a611c53565b9283610ed1610ecb610ec6610ec1610ebc610eae610ea95f8d90610ca0565b610a08565b610eb6610db5565b90610dc6565b610ded565b6109a8565b6100fb565b916100fb565b0361102957610edf84611ea0565b610ef3610eee60018790610cb6565b610ce3565b610f14610f0e610f09610f04610b65565b610e09565b6101b9565b916101b9565b03611022575f94939450610f26610e25565b93610f2f610e25565b95610f3b848690610e29565b60015b15610f7a575b610f71610f6b5f98610f656040610f5f8d8b908d9091610e41565b01610e56565b90610a15565b98610e63565b96979697610f3e565b87610f8d610f878361034c565b9161034c565b10610f44575092610fe1929650610fcc6020610fc6610fe797610fb6610fd2969a9860036109c0565b9490610fc0610b65565b91610e41565b01610e72565b906109d6565b91610fdc83610a08565b610a15565b90610a5d565b61101d7fa1470b3e580ca86a806ba4cff90a8a7327f837f862b313e7c406aa942d62997e916110146100e2565b91829182610541565b0390a1565b9350505050565b6110316100e2565b6310c74b0360e01b8152806110486004820161018a565b0390fd5b5f90565b9061106261105d83610b71565b6107be565b918252565b369037565b9061109161107983611050565b926020806110878693610b71565b9201910390611067565b565b90565b6110aa6110a56110af92611093565b61091b565b61034c565b90565b6110bc60ff611096565b90565b5190565b906110cd826110bf565b8110156110de576020809102010190565b610e2d565b1b90565b611106906111006110fa61110b9461034c565b9161034c565b906110e3565b61034c565b90565b67ffffffffffffffff811161112c57611128602091610777565b0190565b610781565b9061114361113e8361110e565b6107be565b918252565b5f7f72616e646f6d0000000000000000000000000000000000000000000000000000910152565b6111796006611131565b9061118660208301611148565b565b61119061116f565b90565b61119b611188565b90565b906111a8906109b4565b5f5260205260405f2090565b6111bd906109ec565b90565b906111d56111d06111dc92610c94565b6111b4565b8254610a28565b9055565b919290926111ec61104c565b506111f68361106c565b916111ff611c53565b9361120985611ea0565b8061122361121d611218610b65565b61034c565b9161034c565b148015611591575b801561156d575b61154a57611241828890610e29565b611249610e25565b97611252610e25565b9361125b610e25565b9260015b1561151c575b5f9a8761129061128a611285602061127f888a8891610e41565b01610e72565b6100fb565b916100fb565b14806114dd575b6112ab575b6112a590610e63565b9a61125f565b9593611303611309916112e66112d46112cf6112ca888d8b9091610e41565b610d6b565b612702565b6112e18d918a90926110c3565b610d0b565b6112fd60406112f787898d91610e41565b01610e56565b90610a15565b94610e63565b958561131d6113178961034c565b9161034c565b0361129c57505050509293949596509061133b611341915b9261034c565b9161034c565b106114ba578061136061135a611355610b65565b61034c565b9161034c565b11918261148f575b505061146c576113cd6113908261138a6113846113dd9561279d565b916110bf565b90612831565b9383906113a58161139f6110b2565b906110e7565b6113be6113b86113b3610b65565b61034c565b9161034c565b145f146114655743915b612923565b6113d85f8590610ca0565b610a5d565b6114096114026113fd6113f66113f1611193565b612999565b84906129ba565b6129d4565b83906129e9565b61141e826114196002849061119e565b6111c0565b819061145f61144d7f7a1cb491da9915d087844d867ad00ac476b12041d231adb7a04be595db91e44b926109b4565b926114566100e2565b91829182610541565b0390a290565b42916113c8565b6114746100e2565b631884a2c160e21b81528061148b6004820161018a565b0390fd5b8192506114a76114ac916114b2939487919091611cd3565b61034c565b9161034c565b115f80611368565b6114c26100e2565b63d3e0741d60e01b8152806114d96004820161018a565b0390fd5b506115176114ed84868491610e41565b61151261150c611507611502888a8891610e41565b610d6b565b6124f5565b91610d6b565b61259e565b611297565b8a61152f6115298361034c565b9161034c565b10611265575050509293949596509061133b61134191611335565b6115526100e2565b63d3e0741d60e01b8152806115696004820161018a565b0390fd5b508061158b611585611580858b90610e29565b61034c565b9161034c565b11611232565b50806115ac6115a66115a16110b2565b61034c565b9161034c565b1161122b565b5090565b90565b6115cd6115c86115d2926115b6565b61091b565b61034c565b90565b6115df60206115b9565b90565b634e487b7160e01b5f52601260045260245ffd5b6116026116089161034c565b9161034c565b908115611613570490565b6115e2565b61162461162a9161034c565b9161034c565b908115611635570690565b6115e2565b90611644906109b4565b5f5260205260405f2090565b9061165a906109b4565b5f5260205260405f2090565b9061167090610a3e565b5f5260205260405f2090565b5f80fd5b67ffffffffffffffff811161169e5761169a602091610777565b0190565b610781565b90825f939282370152565b909291926116c36116be82611680565b6107be565b938185526020850190828401116116df576116dd926116a3565b565b61167c565b6116ef9136916116ae565b90565b906116fc906109b4565b5f5260205260405f2090565b90611712906109b4565b5f5260205260405f2090565b9061172890610a3e565b5f5260205260405f2090565b9061173e90610a3e565b5f5260205260405f2090565b9061175b60018060a01b0391610a23565b9181191691161790565b90565b9061177d611778611784926109b4565b611765565b825461174a565b9055565b90565b61179f61179a6117a492611788565b61091b565b61034c565b90565b6117b1608061178b565b90565b9160206117d59294936117ce60408201965f8301906108bc565b01906106c9565b565b929190926117f76117e98385906115b2565b6117f16115d5565b906115f6565b926118038382906115b2565b61181c611816611811610b65565b61034c565b9161034c565b14801561195d575b61193a576118db6118f4926118d661187d611878611840611c53565b9561184a87611ea0565b61187261186d61186661185f60048b9061163a565b8890611650565b8d90611666565b610a08565b986116e4565b6129ec565b976118b1896118ac6118a561189e61189760058b906116f2565b8890611708565b859061171e565b8a90611734565b611768565b6118d16118bf888a90610a15565b936118cc6004889061163a565b611650565b611666565b610a5d565b926118ee836118e86117a7565b906110e7565b92610a15565b17916119207f4a9be6e850eedc66e4825f5b36116362dc33883bde2f20bfd7e22c8f6c871202926109b4565b9261193561192c6100e2565b928392836117b4565b0390a2565b6119426100e2565b6321f9f13f60e11b8152806119596004820161018a565b0390fd5b5061197a61196c8483906115b2565b6119746115d5565b90611618565b61199361198d611988610b65565b61034c565b9161034c565b1415611824565b9190916119a561104c565b506119d06119cb6119c66119bf6119ba611193565b612999565b84906129ba565b6129d4565b612a33565b92836119f36119ed6119e86119e3610b65565b610e09565b6101b9565b916101b9565b146119fd575b5050565b90919250611a2057611a13611a1891600261119e565b610ce3565b905f806119f9565b611a286100e2565b63d3e0741d60e01b815280611a3f6004820161018a565b0390fd5b5f90565b60018060a01b031690565b611a5e611a63916109ec565b611a47565b90565b611a709054611a52565b90565b611ad5611ada91611a82611a43565b50611acf6060611ac8611ab6611aa46005611a9e5f8801610e72565b906116f2565b611ab060208701610e72565b90611708565b611ac260408601610e56565b9061171e565b9201610e56565b90611734565b611a66565b90565b611aef90611ae9610b45565b50612a67565b90565b611afc90516100fb565b90565b90611b08611c53565b91611b1283611ea0565b82611b2f611b29611b245f8501611af2565b6100fb565b916100fb565b03611c0857611b5f611b51611b4383612b51565b611b4b6115d5565b906115f6565b611b596115d5565b906115f6565b91611b69826124f5565b938490611bab611b997fbd86c8c76936132dbc24244b04f4607b8bc2b75dd1cb36379bbedeee254b9260926109b4565b92611ba26100e2565b91829182610541565b0390a2611bb6610e25565b9260015b15611be9575b611be35f94611bd28160808701610cfd565b611bdd85889061259e565b50610e63565b93611bba565b83611bfc611bf68361034c565b9161034c565b10611bc0575092505050565b611c106100e2565b6310c74b0360e01b815280611c276004820161018a565b0390fd5b611c5091611c46611c4b92611c3e610e25565b5060036109c0565b6109d6565b610a08565b90565b611c5b611a43565b50335f526e2fd5aeb385d324b580fca7c83823a0803314611cad575b506dd9ecebf3c23529de49815dac1c4c803314611c95575b505f5190565b5f8060209238905afa15611ca9575f611c8f565b3838fd5b5f8060209238905afa15611cc1575f611c77565b3838fd5b90611cd0910361034c565b90565b929192611cde610e25565b50611cfd611cf8611cf1600384906109c0565b84906109d6565b610a08565b9380611d11611d0b8761034c565b9161034c565b115f14611d705750835b9384611d36611d30611d2b610b65565b61034c565b9161034c565b11611d41575b505050565b611d6892611d5e611d56611d63938890611cc5565b9360036109c0565b6109d6565b610a5d565b5f8080611d3c565b611d1b565b91909181611d92611d8c611d87610b65565b61034c565b9161034c565b14611dd85782611db2611dac611da75f61093a565b6100fb565b916100fb565b145f14611dc657611dc39250612c3d565b5b565b90611dd392919091612bff565b611dc4565b505050565b611de6906109a8565b90565b611df1610e25565b5081611e0d611e07611e025f61093a565b6100fb565b916100fb565b145f14611e55575050611e28611e223461034c565b9161034c565b11611e3257345b90565b611e3a6100e2565b631884a2c160e21b815280611e516004820161018a565b0390fd5b81611e87611e9692611e74611e9b9695611e6e30611ddd565b90612c5b565b948391611e8030611ddd565b9192612c89565b611e9030611ddd565b90612c5b565b611cc5565b611e2f565b34611eba611eb4611eaf610b65565b61034c565b9161034c565b11611ec3575b50565b611efd90611ef7611ee8611ed9349360036109c0565b611ee25f61093a565b906109d6565b91611ef283610a08565b610a15565b90610a5d565b5f611ec0565b611f0d90516101b9565b90565b611f24611f1f611f2992610918565b610a23565b6101b9565b90565b916020611f4d929493611f4660408201965f830190610534565b0190610534565b565b909192611f5a610b45565b50611f63610e25565b93611f6f848290610e29565b93611f84611f7f60018690610cb6565b610ce3565b611fa5611f9f611f9a611f95610b65565b610e09565b6101b9565b916101b9565b0361223257611fb38561106c565b93611fbc610e25565b95611fc5610b45565b50611fce610b45565b9060015b156120f5575b5f98611fed611fe88883906110c3565b611f03565b612007612001611ffc5f611f10565b6101b9565b916101b9565b14155f1461207a5761205061203a61202187898591610e41565b61203461202f8b86906110c3565b611f03565b90612df5565b61204b8b93929391859094926110c3565b610d0b565b612065575b61205f905b610e63565b98611fd2565b9761207261205f91610e63565b989050612055565b6120a361209161208c87898591610e41565b612d1c565b61209e89918490926110c3565b610d0b565b6120b66120b18883906110c3565b611f03565b6120d76120d16120cc6120c7610b65565b610e09565b6101b9565b916101b9565b146120e6575b61205f9061205a565b915061205f60019290506120dd565b886121086121028361034c565b9161034c565b10611fd857509093965094919390946122015761214961214361213e85936121386121328261279d565b916110bf565b90612831565b6101b9565b916101b9565b036121de576121d99461217c612181926121766121675f8790610ca0565b9161217183610a08565b610a15565b90610a5d565b61279d565b6121968161219160018590610cb6565b6111c0565b81907f46adc4912184d61bbcd0939b961e9388a3fa9122b827b48b36fdf552759f3e7d916121ce6121c56100e2565b92839283611f2c565b0390a1919091613076565b600190565b6121e66100e2565b635c49863b60e11b8152806121fd6004820161018a565b0390fd5b5061222e94506122199193506122289250925f610ca0565b9161222383610a08565b610a15565b90610a5d565b5f90565b5050505050505f90565b634e487b7160e01b5f52601160045260245ffd5b61225c6122629161034c565b9161034c565b90811561226d570490565b6115e2565b61227c905161034c565b90565b90612289906109b4565b5f5260205260405f2090565b9061229f906109b4565b5f5260205260405f2090565b906122b590610a3e565b5f5260205260405f2090565b6122d06122d69193929361034c565b9261034c565b82018092116122e157565b61223c565b90565b6122fd6122f8612302926122e6565b61091b565b61034c565b90565b6123106101006122e9565b90565b6123226123289193929361034c565b9261034c565b820391821161233357565b61223c565b90565b61234f61234a61235492612338565b61091b565b61034c565b90565b612361600161233b565b90565b61236c610b45565b5061238761237982612b51565b6123816115d5565b90612250565b6123a461239e61239960808501612272565b61034c565b9161034c565b11156124aa5761247f61248d916124796124376124326123fa6123e86123d660066123d05f8901611af2565b9061227f565b6123e260208801611af2565b90612295565b6123f460408701612272565b906122ab565b61242c61241e61240c60808801612272565b61241860608901612272565b906122c1565b612426612305565b90612250565b90611666565b610a08565b916124736124656124466110b2565b9261245f606061245860808401612272565b9201612272565b906122c1565b61246d612305565b90611618565b90612313565b906110e7565b6124876110b2565b90610dc6565b6124a66124a061249b612357565b61034c565b9161034c565b1490565b6124b26100e2565b6321f9f13f60e11b8152806124c96004820161018a565b0390fd5b6124d69061098c565b90565b6124ed6124e86124f2926100f0565b61091b565b61034c565b90565b6125789061250161104c565b5061252561252061251b6125165f8501611af2565b6124cd565b6124d9565b610e09565b9061254a61254561254061253b60208501611af2565b6124cd565b6124d9565b610e09565b61257261256d606061256661256160408701612272565b610e09565b9401612272565b610e09565b9261322e565b90565b91602061259c92949361259560408201965f830190610534565b01906108bc565b565b906125a7610b45565b506125b182612364565b6126fc576126876125fb6125c3612357565b6125f56125e76125d560608801612272565b6125e160808901612272565b90610a15565b6125ef612305565b90611618565b906110e7565b61267661263e61262c61261a60066126145f8a01611af2565b9061227f565b61262660208901611af2565b90612295565b61263860408801612272565b906122ab565b61267061266261265060608901612272565b61265c60808a01612272565b90610a15565b61266a612305565b906115f6565b90611666565b9061268082610a08565b1790610a5d565b6126b56126955f8401611af2565b91926126af60806126a860608401612272565b9201612272565b90610a15565b6126df7fed034d9d62bb699c05145f178d69dcac2bbbe1b6ab1bb196ac35b5d0bd00e2d0926109b4565b926126f46126eb6100e2565b9283928361257b565b0390a2600190565b50505f90565b61279a9061270e61104c565b5061273261272d6127286127235f8501611af2565b6124cd565b6124d9565b610e09565b9061275761275261274d61274860208501611af2565b6124cd565b6124d9565b610e09565b61276b61276660408401612272565b610e09565b9061279461278f608061278861278360608801612272565b610e09565b9501612272565b610e09565b93613255565b90565b6127a561104c565b506020815160051b91012090565b6127bf6127c4916109ec565b610a3e565b90565b90565b6127de6127d96127e3926127c7565b61091b565b61034c565b90565b6127f060086127ca565b90565b60ff1690565b61280d6128086128129261034c565b61091b565b6127f3565b90565b61282961282461282e926127f3565b61091b565b61034c565b90565b9061286961286461285e61285061286f9561284a61104c565b506127b3565b6128586127e6565b906110e7565b926127f9565b612815565b17610e09565b90565b65ffffffffffff1690565b61289161288c6128969261034c565b61091b565b612872565b90565b6128ad6128a86128b292612872565b61091b565b61034c565b90565b90565b6128cc6128c76128d1926128b5565b61091b565b61034c565b90565b6128de60306128b8565b90565b64ffffffffff1690565b6128ff6128fa6129049261034c565b61091b565b6128e1565b90565b61291b612916612920926128e1565b61091b565b61034c565b90565b612982612995929361297b61296d61296861296261295461294f61298798612949610e25565b506124cd565b6124d9565b61295c610db5565b906110e7565b9361287d565b612899565b6129756128d4565b906110e7565b17936128eb565b612907565b61298f6127e6565b906110e7565b1790565b6001906129a461104c565b5060208151910120035f5260ff1960205f201690565b906129c361104c565b505f5260205260405f2090565b5f90565b6129e6906129e06129d0565b50610c94565b90565b5d565b906129f5611a43565b5081518060401b6bfe61000180600a3d393df3000161fffe8211840152600b8101601584015ff0928315612a265752565b63301164255f526004601cfd5b612a3b61104c565b505c90565b612a5f90612a59612a53612a649461034c565b916128e1565b90610dc2565b6128e1565b90565b612a6f610b45565b50612aa4612a9682612a90612a826110b2565b612a8a6127e6565b90611cc5565b906110e7565b612a9e6110b2565b90610dc6565b612abd612ab7612ab2610b65565b61034c565b9161034c565b145f14612b3957612b35612b2f612b2a612b25612b06612b00435b612afa612af5612af08a612aea6128d4565b90610dc6565b61287d565b612899565b90611cc5565b956128eb565b612b1f612b116127e6565b612b19612357565b90610a15565b90612a40565b612907565b61034c565b9161034c565b1190565b612b35612b2f612b2a612b25612b06612b0042612ad8565b612bb3612bb891612b60610e25565b50612bad6060612ba6612b94612b826005612b7c5f8801611af2565b906116f2565b612b8e60208701611af2565b90611708565b612ba060408601612272565b9061171e565b9201612272565b90611734565b611a66565b80612bd3612bcd612bc85f61093a565b6100fb565b916100fb565b14612bdc573b90565b612be46100e2565b6321f9f13f60e11b815280612bfb6004820161018a565b0390fd5b60105f604492602095829560145260345263a9059cbb60601b82525af13d1560015f5114171615612c30575f603452565b6390b8ec185f526004601cfd5b905f8092389238915af115612c4e57565b63b12d13eb5f526004601cfd5b60246010602093928493612c6d610e25565b506014526370a0823160601b5f525afa601f3d11166020510290565b929091612ca3612c9d858584908692613283565b156102d4565b612cae575b50505050565b612cbb93929091926132ca565b5f808080612ca8565b90612cce906109b4565b5f5260205260405f2090565b90612ce4906109b4565b5f5260205260405f2090565b90612cfa90610a3e565b5f5260205260405f2090565b90612d1090610a3e565b5f5260205260405f2090565b612d94612d9991612d2b61104c565b50612d8e612d6f612d5d612d4b6007612d455f8701610e72565b90612cc4565b612d5760208601610e72565b90612cda565b612d6960408501610e56565b90612cf0565b91612d886080612d8160608401610e56565b9201610e56565b906122c1565b90612d06565b610ce3565b90565b90612da7910261034c565b90565b5190565b60200190565b612dce612dc9612dc383612daa565b92612dae565b611f03565b9060208110612ddc575b5090565b612dee905f19906020036008026110e3565b165f612dd8565b90612dfe61104c565b50612e07610b45565b50612e65612e60612e4e612e3c612e2a6005612e245f8901610e72565b906116f2565b612e3660208801610e72565b90611708565b612e4860408701610e56565b9061171e565b612e5a60608601610e56565b90611734565b611a66565b80612e80612e7a612e755f61093a565b6100fb565b916100fb565b1461303457612efc612ef6612ef1612eec612e9a86613357565b94612eb8612eaa60808a01610e56565b612eb26115d5565b90612d9c565b612ee6612ed8612eca60808c01610e56565b612ed26115d5565b90612d9c565b612ee06115d5565b90610a15565b9161336e565b612db4565b6101b9565b916101b9565b0361301157612f12612f0d83610d6b565b612702565b91612f1c81612d1c565b612f3d612f37612f32612f2d610b65565b610e09565b6101b9565b916101b9565b14612f49575050905f90565b5f612fc791612fc184612fbc612f95612f83612f716007612f6b898901610e72565b90612cc4565b612f7d60208801610e72565b90612cda565b612f8f60408701610e56565b90612cf0565b612fb6612fa460608701610e56565b612fb060808801610e56565b90610a15565b90612d06565b6111c0565b01610e72565b8291612ff37fa8080584ebb92497a93bf0923d88f7a218d6b2b12e73938ec37157d8df9c561e926109b4565b92613008612fff6100e2565b92839283611f2c565b0390a290600190565b6130196100e2565b63162c5b6560e01b8152806130306004820161018a565b0390fd5b61303c6100e2565b6321f9f13f60e11b8152806130536004820161018a565b0390fd5b90565b61306e61306961307392613057565b61091b565b61034c565b90565b9161309c90939193613089858290610e29565b94906130968587906133e6565b91610e41565b906130a5610e25565b926130ae610e25565b9460015b156130e1575b6130d86130d25f966130cc60408801610e56565b90610a15565b96610e63565b949594956130b2565b856130f46130ee8361034c565b9161034c565b106130b85750613161919450613167936131529161312361311e6131195f8490610ca0565b610a08565b612a67565b613169575b509261314c6020613145600361313f5f8601610e72565b906109c0565b9201610e72565b906109d6565b9161315c83610a08565b610a15565b90610a5d565b565b906131ce613175611c53565b9161318a81613184600261305a565b906115f6565b6131c8816131c26131b38b6131ad60206131a660038c906109c0565b9201610e72565b906109d6565b916131bd83610a08565b610a15565b90610a5d565b90611cc5565b916131da5f8701610e72565b91909161322561321361320d7f3781e851432a339d869c35381daaa3d38116d4c213be17a65bd47ca16c450409936109b4565b936109b4565b9361321c6100e2565b91829182610541565b0390a35f613128565b916080939161323b61104c565b506040519384526020840152604083015260608201522090565b92909160a0949261326461104c565b5060405194855260208501526040840152606083015260808201522090565b601c5f6064928194602096989798613299610b45565b506040519960605260405260601b602c526323b872dd60601b600c525af13d1560015f51141716915f606052604052565b916040519260601b60601c6074840152836054840152603483015260601b6020820152631b63c28b60611b81526e22d473030f116ddee9f6b43ac78ba39060014614908115613346575b60845f9293836010389401915af1161561332b5750565b600490677939f4248757f0fd5f5260a01c151560021b601801fd5b5f91506084833b1515925050613314565b61335f61104c565b505f5260205f2090565b606090565b909291613379613369565b506040519380820361ffff16926001840182601f8801833c8386015160ff16156133b6575b5010810283525f816020850101526040830101604052565b9060018194923b03918260401c3d3d3e828403838511029003911102915f61339e565b6133e360206107be565b90565b9061340e613409613404613427946133fc610e25565b506001610cb6565b610ce3565b6127b3565b6134226134196133d9565b915f8301610cfd565b61342a565b90565b613432610e25565b505b6020812080825282805f030681101561344d5750613434565b9050069056fea2646970667358221220465da8eeb7695e18cd7a7179f1f70cb5226d5cb328ff6c1a4a1dcff3cd4fca4964736f6c63430008190033

Deployed ByteCode

0x60806040526004361015610013575b610914565b61001d5f356100dc565b806302a381bf146100d757806307bbadd7146100d25780630cf9dff7146100cd5780631ff3434f146100c85780635312f336146100c357806358e5abde146100be57806362fd0d1f146100b95780638492c30b146100b4578063870c096a146100af578063ba065e1f146100aa578063c464e628146100a55763f7888aec0361000e576108de565b610866565b61073e565b6106eb565b610693565b610616565b610556565b610487565b61040c565b6103a2565b6102fb565b61018f565b60e01c90565b60405190565b5f80fd5b5f80fd5b60018060a01b031690565b610104906100f0565b90565b610110816100fb565b0361011757565b5f80fd5b9050359061012882610107565b565b90565b6101368161012a565b0361013d57565b5f80fd5b9050359061014e8261012d565b565b90916060828403126101855761018261016b845f850161011b565b93610179816020860161011b565b93604001610141565b90565b6100e8565b5f0190565b6101a361019d366004610150565b91610a7d565b6101ab6100e2565b806101b58161018a565b0390f35b90565b6101c5816101b9565b036101cc57565b5f80fd5b905035906101dd826101bc565b565b5f80fd5b5f80fd5b5f80fd5b909182601f830112156102255781359167ffffffffffffffff8311610220576020019260a0830284011161021b57565b6101e7565b6101e3565b6101df565b909182601f830112156102645781359167ffffffffffffffff831161025f57602001926020830284011161025a57565b6101e7565b6101e3565b6101df565b6060818303126102cf5761027f825f83016101d0565b92602082013567ffffffffffffffff81116102ca57836102a09184016101eb565b929093604082013567ffffffffffffffff81116102c5576102c1920161022a565b9091565b6100ec565b6100ec565b6100e8565b151590565b6102e2906102d4565b9052565b91906102f9905f602085019401906102d9565b565b61032661031561030c366004610269565b93929092610bf3565b61031d6100e2565b918291826102e6565b0390f35b5f80fd5b9060208282031261034757610344915f016101d0565b90565b6100e8565b90565b6103589061034c565b9052565b610365906101b9565b9052565b9060208061038b936103815f8201515f86019061034f565b015191019061035c565b565b91906103a0905f60408501940190610369565b565b346103d2576103ce6103bd6103b836600461032e565b610d19565b6103c56100e2565b9182918261038d565b0390f35b61032a565b5f80fd5b908160a09103126103e95790565b6103d7565b9060a08282031261040757610404915f016103db565b90565b6100e8565b3461043c576104386104276104223660046103ee565b610d79565b61042f6100e2565b918291826102e6565b0390f35b61032a565b9190916040818403126104825761045a835f83016101d0565b92602082013567ffffffffffffffff811161047d5761047992016101eb565b9091565b6100ec565b6100e8565b61049b610495366004610441565b91610e7f565b6104a36100e2565b806104ad8161018a565b0390f35b6104ba8161034c565b036104c157565b5f80fd5b905035906104d2826104b1565b565b9060808282031261052f576104eb815f84016104c5565b926104f982602085016104c5565b92610507836040830161011b565b92606082013567ffffffffffffffff811161052a5761052692016101eb565b9091565b6100ec565b6100e8565b61053d906101b9565b9052565b9190610554905f60208501940190610534565b565b6105816105706105673660046104d4565b939290926111e0565b6105786100e2565b91829182610541565b0390f35b909182601f830112156105bf5781359167ffffffffffffffff83116105ba5760200192600183028401116105b557565b6101e7565b6101e3565b6101df565b91606083830312610611576105db825f850161011b565b926105e983602083016104c5565b92604082013567ffffffffffffffff811161060c576106089201610585565b9091565b6100ec565b6100e8565b61062d6106243660046105c4565b929190916117d7565b6106356100e2565b8061063f8161018a565b0390f35b61064c816102d4565b0361065357565b5f80fd5b9050359061066482610643565b565b919060408382031261068e578061068261068b925f860161011b565b93602001610657565b90565b6100e8565b346106c4576106c06106af6106a9366004610666565b9061199a565b6106b76100e2565b91829182610541565b0390f35b61032a565b6106d2906100fb565b9052565b91906106e9905f602085019401906106c9565b565b3461071b576107176107066107013660046103ee565b611a73565b61070e6100e2565b918291826106d6565b0390f35b61032a565b9060208282031261073957610736915f016104c5565b90565b6100e8565b3461076e5761076a610759610754366004610720565b611add565b6107616100e2565b918291826102e6565b0390f35b61032a565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061079f90610777565b810190811067ffffffffffffffff8211176107b957604052565b610781565b906107d16107ca6100e2565b9283610795565b565b919060a0838203126108435761083c906107ed60a06107be565b936107fa825f830161011b565b5f86015261080b826020830161011b565b602086015261081d82604083016104c5565b604086015261082f82606083016104c5565b60608601526080016104c5565b6080830152565b610773565b9060a0828203126108615761085e915f016107d3565b90565b6100e8565b610879610874366004610848565b611aff565b6108816100e2565b8061088b8161018a565b0390f35b91906040838203126108b757806108ab6108b4925f860161011b565b9360200161011b565b90565b6100e8565b6108c59061034c565b9052565b91906108dc905f602085019401906108bc565b565b3461090f5761090b6108fa6108f436600461088f565b90611c2b565b6109026100e2565b918291826108c9565b0390f35b61032a565b5f80fd5b90565b90565b61093261092d61093792610918565b61091b565b6100f0565b90565b6109439061091e565b90565b61095a61095561095f92610918565b61091b565b61012a565b90565b61097661097161097b9261012a565b61091b565b61034c565b90565b610989905f0361012a565b90565b6109a061099b6109a5926100f0565b61091b565b6100f0565b90565b6109b19061098c565b90565b6109bd906109a8565b90565b906109ca906109b4565b5f5260205260405f2090565b906109e0906109b4565b5f5260205260405f2090565b5f1c90565b90565b610a00610a05916109ec565b6109f1565b90565b610a1290546109f4565b90565b90610a20910161034c565b90565b5f1b90565b90610a345f1991610a23565b9181191691161790565b610a52610a4d610a579261034c565b61091b565b61034c565b90565b90565b90610a72610a6d610a7992610a3e565b610a5a565b8254610a28565b9055565b9091610a87611c53565b9180610aa3610a9d610a985f61093a565b6100fb565b916100fb565b145f14610b405750815b9181610ac1610abb5f610946565b9161012a565b125f14610b1857610b1593610afb610af3610b0f94610b009490610aed610ae8869261097e565b610962565b91611de9565b9460036109c0565b6109d6565b91610b0a83610a08565b610a15565b90610a5d565b5b565b9091610b3b93610b359193610b2f82949291610962565b91611cd3565b91611d75565b610b16565b610aad565b5f90565b610b5d610b58610b6292610918565b61091b565b61034c565b90565b610b6e5f610b49565b90565b67ffffffffffffffff8111610b895760208091020190565b610781565b90929192610ba3610b9e82610b71565b6107be565b9381855260208086019202830192818411610be057915b838310610bc75750505050565b60208091610bd584866101d0565b815201920191610bba565b6101e7565b610bf0913691610b8e565b90565b610c3694610c309194939294610c07610b45565b5034610c22610c1c610c17610b65565b61034c565b9161034c565b11610c39575b949293610be5565b92611f4f565b90565b610c49610c44611c53565b611ea0565b610c28565b610c5860406107be565b90565b5f90565b5f90565b610c6b610c4e565b9060208083610c78610c5b565b815201610c83610c5f565b81525050565b610c91610c63565b90565b610c9d906101b9565b90565b90610caa90610c94565b5f5260205260405f2090565b90610cc090610c94565b5f5260205260405f2090565b90565b610cdb610ce0916109ec565b610ccc565b90565b610ced9054610ccf565b90565b610cfa60406107be565b90565b90610d079061034c565b9052565b90610d15906101b9565b9052565b610d21610c89565b50610d68610d4b610d46610d3e610d395f8690610ca0565b610a08565b936001610cb6565b610ce3565b610d5f610d56610cf0565b935f8501610cfd565b60208301610d0b565b90565b610d769036906107d3565b90565b610d8e610d9391610d88610b45565b50610d6b565b612364565b90565b90565b610dad610da8610db292610d96565b61091b565b61034c565b90565b610dbf6060610d99565b90565b1c90565b610de590610ddf610dd9610dea9461034c565b9161034c565b90610dc2565b61034c565b90565b610e01610dfc610e069261034c565b61091b565b6100f0565b90565b610e1d610e18610e229261034c565b610a23565b6101b9565b90565b5f90565b5090565b634e487b7160e01b5f52603260045260245ffd5b9190811015610e515760a0020190565b610e2d565b35610e60816104b1565b90565b6001610e6f910161034c565b90565b35610e7c81610107565b90565b929190610e8a611c53565b9283610ed1610ecb610ec6610ec1610ebc610eae610ea95f8d90610ca0565b610a08565b610eb6610db5565b90610dc6565b610ded565b6109a8565b6100fb565b916100fb565b0361102957610edf84611ea0565b610ef3610eee60018790610cb6565b610ce3565b610f14610f0e610f09610f04610b65565b610e09565b6101b9565b916101b9565b03611022575f94939450610f26610e25565b93610f2f610e25565b95610f3b848690610e29565b60015b15610f7a575b610f71610f6b5f98610f656040610f5f8d8b908d9091610e41565b01610e56565b90610a15565b98610e63565b96979697610f3e565b87610f8d610f878361034c565b9161034c565b10610f44575092610fe1929650610fcc6020610fc6610fe797610fb6610fd2969a9860036109c0565b9490610fc0610b65565b91610e41565b01610e72565b906109d6565b91610fdc83610a08565b610a15565b90610a5d565b61101d7fa1470b3e580ca86a806ba4cff90a8a7327f837f862b313e7c406aa942d62997e916110146100e2565b91829182610541565b0390a1565b9350505050565b6110316100e2565b6310c74b0360e01b8152806110486004820161018a565b0390fd5b5f90565b9061106261105d83610b71565b6107be565b918252565b369037565b9061109161107983611050565b926020806110878693610b71565b9201910390611067565b565b90565b6110aa6110a56110af92611093565b61091b565b61034c565b90565b6110bc60ff611096565b90565b5190565b906110cd826110bf565b8110156110de576020809102010190565b610e2d565b1b90565b611106906111006110fa61110b9461034c565b9161034c565b906110e3565b61034c565b90565b67ffffffffffffffff811161112c57611128602091610777565b0190565b610781565b9061114361113e8361110e565b6107be565b918252565b5f7f72616e646f6d0000000000000000000000000000000000000000000000000000910152565b6111796006611131565b9061118660208301611148565b565b61119061116f565b90565b61119b611188565b90565b906111a8906109b4565b5f5260205260405f2090565b6111bd906109ec565b90565b906111d56111d06111dc92610c94565b6111b4565b8254610a28565b9055565b919290926111ec61104c565b506111f68361106c565b916111ff611c53565b9361120985611ea0565b8061122361121d611218610b65565b61034c565b9161034c565b148015611591575b801561156d575b61154a57611241828890610e29565b611249610e25565b97611252610e25565b9361125b610e25565b9260015b1561151c575b5f9a8761129061128a611285602061127f888a8891610e41565b01610e72565b6100fb565b916100fb565b14806114dd575b6112ab575b6112a590610e63565b9a61125f565b9593611303611309916112e66112d46112cf6112ca888d8b9091610e41565b610d6b565b612702565b6112e18d918a90926110c3565b610d0b565b6112fd60406112f787898d91610e41565b01610e56565b90610a15565b94610e63565b958561131d6113178961034c565b9161034c565b0361129c57505050509293949596509061133b611341915b9261034c565b9161034c565b106114ba578061136061135a611355610b65565b61034c565b9161034c565b11918261148f575b505061146c576113cd6113908261138a6113846113dd9561279d565b916110bf565b90612831565b9383906113a58161139f6110b2565b906110e7565b6113be6113b86113b3610b65565b61034c565b9161034c565b145f146114655743915b612923565b6113d85f8590610ca0565b610a5d565b6114096114026113fd6113f66113f1611193565b612999565b84906129ba565b6129d4565b83906129e9565b61141e826114196002849061119e565b6111c0565b819061145f61144d7f7a1cb491da9915d087844d867ad00ac476b12041d231adb7a04be595db91e44b926109b4565b926114566100e2565b91829182610541565b0390a290565b42916113c8565b6114746100e2565b631884a2c160e21b81528061148b6004820161018a565b0390fd5b8192506114a76114ac916114b2939487919091611cd3565b61034c565b9161034c565b115f80611368565b6114c26100e2565b63d3e0741d60e01b8152806114d96004820161018a565b0390fd5b506115176114ed84868491610e41565b61151261150c611507611502888a8891610e41565b610d6b565b6124f5565b91610d6b565b61259e565b611297565b8a61152f6115298361034c565b9161034c565b10611265575050509293949596509061133b61134191611335565b6115526100e2565b63d3e0741d60e01b8152806115696004820161018a565b0390fd5b508061158b611585611580858b90610e29565b61034c565b9161034c565b11611232565b50806115ac6115a66115a16110b2565b61034c565b9161034c565b1161122b565b5090565b90565b6115cd6115c86115d2926115b6565b61091b565b61034c565b90565b6115df60206115b9565b90565b634e487b7160e01b5f52601260045260245ffd5b6116026116089161034c565b9161034c565b908115611613570490565b6115e2565b61162461162a9161034c565b9161034c565b908115611635570690565b6115e2565b90611644906109b4565b5f5260205260405f2090565b9061165a906109b4565b5f5260205260405f2090565b9061167090610a3e565b5f5260205260405f2090565b5f80fd5b67ffffffffffffffff811161169e5761169a602091610777565b0190565b610781565b90825f939282370152565b909291926116c36116be82611680565b6107be565b938185526020850190828401116116df576116dd926116a3565b565b61167c565b6116ef9136916116ae565b90565b906116fc906109b4565b5f5260205260405f2090565b90611712906109b4565b5f5260205260405f2090565b9061172890610a3e565b5f5260205260405f2090565b9061173e90610a3e565b5f5260205260405f2090565b9061175b60018060a01b0391610a23565b9181191691161790565b90565b9061177d611778611784926109b4565b611765565b825461174a565b9055565b90565b61179f61179a6117a492611788565b61091b565b61034c565b90565b6117b1608061178b565b90565b9160206117d59294936117ce60408201965f8301906108bc565b01906106c9565b565b929190926117f76117e98385906115b2565b6117f16115d5565b906115f6565b926118038382906115b2565b61181c611816611811610b65565b61034c565b9161034c565b14801561195d575b61193a576118db6118f4926118d661187d611878611840611c53565b9561184a87611ea0565b61187261186d61186661185f60048b9061163a565b8890611650565b8d90611666565b610a08565b986116e4565b6129ec565b976118b1896118ac6118a561189e61189760058b906116f2565b8890611708565b859061171e565b8a90611734565b611768565b6118d16118bf888a90610a15565b936118cc6004889061163a565b611650565b611666565b610a5d565b926118ee836118e86117a7565b906110e7565b92610a15565b17916119207f4a9be6e850eedc66e4825f5b36116362dc33883bde2f20bfd7e22c8f6c871202926109b4565b9261193561192c6100e2565b928392836117b4565b0390a2565b6119426100e2565b6321f9f13f60e11b8152806119596004820161018a565b0390fd5b5061197a61196c8483906115b2565b6119746115d5565b90611618565b61199361198d611988610b65565b61034c565b9161034c565b1415611824565b9190916119a561104c565b506119d06119cb6119c66119bf6119ba611193565b612999565b84906129ba565b6129d4565b612a33565b92836119f36119ed6119e86119e3610b65565b610e09565b6101b9565b916101b9565b146119fd575b5050565b90919250611a2057611a13611a1891600261119e565b610ce3565b905f806119f9565b611a286100e2565b63d3e0741d60e01b815280611a3f6004820161018a565b0390fd5b5f90565b60018060a01b031690565b611a5e611a63916109ec565b611a47565b90565b611a709054611a52565b90565b611ad5611ada91611a82611a43565b50611acf6060611ac8611ab6611aa46005611a9e5f8801610e72565b906116f2565b611ab060208701610e72565b90611708565b611ac260408601610e56565b9061171e565b9201610e56565b90611734565b611a66565b90565b611aef90611ae9610b45565b50612a67565b90565b611afc90516100fb565b90565b90611b08611c53565b91611b1283611ea0565b82611b2f611b29611b245f8501611af2565b6100fb565b916100fb565b03611c0857611b5f611b51611b4383612b51565b611b4b6115d5565b906115f6565b611b596115d5565b906115f6565b91611b69826124f5565b938490611bab611b997fbd86c8c76936132dbc24244b04f4607b8bc2b75dd1cb36379bbedeee254b9260926109b4565b92611ba26100e2565b91829182610541565b0390a2611bb6610e25565b9260015b15611be9575b611be35f94611bd28160808701610cfd565b611bdd85889061259e565b50610e63565b93611bba565b83611bfc611bf68361034c565b9161034c565b10611bc0575092505050565b611c106100e2565b6310c74b0360e01b815280611c276004820161018a565b0390fd5b611c5091611c46611c4b92611c3e610e25565b5060036109c0565b6109d6565b610a08565b90565b611c5b611a43565b50335f526e2fd5aeb385d324b580fca7c83823a0803314611cad575b506dd9ecebf3c23529de49815dac1c4c803314611c95575b505f5190565b5f8060209238905afa15611ca9575f611c8f565b3838fd5b5f8060209238905afa15611cc1575f611c77565b3838fd5b90611cd0910361034c565b90565b929192611cde610e25565b50611cfd611cf8611cf1600384906109c0565b84906109d6565b610a08565b9380611d11611d0b8761034c565b9161034c565b115f14611d705750835b9384611d36611d30611d2b610b65565b61034c565b9161034c565b11611d41575b505050565b611d6892611d5e611d56611d63938890611cc5565b9360036109c0565b6109d6565b610a5d565b5f8080611d3c565b611d1b565b91909181611d92611d8c611d87610b65565b61034c565b9161034c565b14611dd85782611db2611dac611da75f61093a565b6100fb565b916100fb565b145f14611dc657611dc39250612c3d565b5b565b90611dd392919091612bff565b611dc4565b505050565b611de6906109a8565b90565b611df1610e25565b5081611e0d611e07611e025f61093a565b6100fb565b916100fb565b145f14611e55575050611e28611e223461034c565b9161034c565b11611e3257345b90565b611e3a6100e2565b631884a2c160e21b815280611e516004820161018a565b0390fd5b81611e87611e9692611e74611e9b9695611e6e30611ddd565b90612c5b565b948391611e8030611ddd565b9192612c89565b611e9030611ddd565b90612c5b565b611cc5565b611e2f565b34611eba611eb4611eaf610b65565b61034c565b9161034c565b11611ec3575b50565b611efd90611ef7611ee8611ed9349360036109c0565b611ee25f61093a565b906109d6565b91611ef283610a08565b610a15565b90610a5d565b5f611ec0565b611f0d90516101b9565b90565b611f24611f1f611f2992610918565b610a23565b6101b9565b90565b916020611f4d929493611f4660408201965f830190610534565b0190610534565b565b909192611f5a610b45565b50611f63610e25565b93611f6f848290610e29565b93611f84611f7f60018690610cb6565b610ce3565b611fa5611f9f611f9a611f95610b65565b610e09565b6101b9565b916101b9565b0361223257611fb38561106c565b93611fbc610e25565b95611fc5610b45565b50611fce610b45565b9060015b156120f5575b5f98611fed611fe88883906110c3565b611f03565b612007612001611ffc5f611f10565b6101b9565b916101b9565b14155f1461207a5761205061203a61202187898591610e41565b61203461202f8b86906110c3565b611f03565b90612df5565b61204b8b93929391859094926110c3565b610d0b565b612065575b61205f905b610e63565b98611fd2565b9761207261205f91610e63565b989050612055565b6120a361209161208c87898591610e41565b612d1c565b61209e89918490926110c3565b610d0b565b6120b66120b18883906110c3565b611f03565b6120d76120d16120cc6120c7610b65565b610e09565b6101b9565b916101b9565b146120e6575b61205f9061205a565b915061205f60019290506120dd565b886121086121028361034c565b9161034c565b10611fd857509093965094919390946122015761214961214361213e85936121386121328261279d565b916110bf565b90612831565b6101b9565b916101b9565b036121de576121d99461217c612181926121766121675f8790610ca0565b9161217183610a08565b610a15565b90610a5d565b61279d565b6121968161219160018590610cb6565b6111c0565b81907f46adc4912184d61bbcd0939b961e9388a3fa9122b827b48b36fdf552759f3e7d916121ce6121c56100e2565b92839283611f2c565b0390a1919091613076565b600190565b6121e66100e2565b635c49863b60e11b8152806121fd6004820161018a565b0390fd5b5061222e94506122199193506122289250925f610ca0565b9161222383610a08565b610a15565b90610a5d565b5f90565b5050505050505f90565b634e487b7160e01b5f52601160045260245ffd5b61225c6122629161034c565b9161034c565b90811561226d570490565b6115e2565b61227c905161034c565b90565b90612289906109b4565b5f5260205260405f2090565b9061229f906109b4565b5f5260205260405f2090565b906122b590610a3e565b5f5260205260405f2090565b6122d06122d69193929361034c565b9261034c565b82018092116122e157565b61223c565b90565b6122fd6122f8612302926122e6565b61091b565b61034c565b90565b6123106101006122e9565b90565b6123226123289193929361034c565b9261034c565b820391821161233357565b61223c565b90565b61234f61234a61235492612338565b61091b565b61034c565b90565b612361600161233b565b90565b61236c610b45565b5061238761237982612b51565b6123816115d5565b90612250565b6123a461239e61239960808501612272565b61034c565b9161034c565b11156124aa5761247f61248d916124796124376124326123fa6123e86123d660066123d05f8901611af2565b9061227f565b6123e260208801611af2565b90612295565b6123f460408701612272565b906122ab565b61242c61241e61240c60808801612272565b61241860608901612272565b906122c1565b612426612305565b90612250565b90611666565b610a08565b916124736124656124466110b2565b9261245f606061245860808401612272565b9201612272565b906122c1565b61246d612305565b90611618565b90612313565b906110e7565b6124876110b2565b90610dc6565b6124a66124a061249b612357565b61034c565b9161034c565b1490565b6124b26100e2565b6321f9f13f60e11b8152806124c96004820161018a565b0390fd5b6124d69061098c565b90565b6124ed6124e86124f2926100f0565b61091b565b61034c565b90565b6125789061250161104c565b5061252561252061251b6125165f8501611af2565b6124cd565b6124d9565b610e09565b9061254a61254561254061253b60208501611af2565b6124cd565b6124d9565b610e09565b61257261256d606061256661256160408701612272565b610e09565b9401612272565b610e09565b9261322e565b90565b91602061259c92949361259560408201965f830190610534565b01906108bc565b565b906125a7610b45565b506125b182612364565b6126fc576126876125fb6125c3612357565b6125f56125e76125d560608801612272565b6125e160808901612272565b90610a15565b6125ef612305565b90611618565b906110e7565b61267661263e61262c61261a60066126145f8a01611af2565b9061227f565b61262660208901611af2565b90612295565b61263860408801612272565b906122ab565b61267061266261265060608901612272565b61265c60808a01612272565b90610a15565b61266a612305565b906115f6565b90611666565b9061268082610a08565b1790610a5d565b6126b56126955f8401611af2565b91926126af60806126a860608401612272565b9201612272565b90610a15565b6126df7fed034d9d62bb699c05145f178d69dcac2bbbe1b6ab1bb196ac35b5d0bd00e2d0926109b4565b926126f46126eb6100e2565b9283928361257b565b0390a2600190565b50505f90565b61279a9061270e61104c565b5061273261272d6127286127235f8501611af2565b6124cd565b6124d9565b610e09565b9061275761275261274d61274860208501611af2565b6124cd565b6124d9565b610e09565b61276b61276660408401612272565b610e09565b9061279461278f608061278861278360608801612272565b610e09565b9501612272565b610e09565b93613255565b90565b6127a561104c565b506020815160051b91012090565b6127bf6127c4916109ec565b610a3e565b90565b90565b6127de6127d96127e3926127c7565b61091b565b61034c565b90565b6127f060086127ca565b90565b60ff1690565b61280d6128086128129261034c565b61091b565b6127f3565b90565b61282961282461282e926127f3565b61091b565b61034c565b90565b9061286961286461285e61285061286f9561284a61104c565b506127b3565b6128586127e6565b906110e7565b926127f9565b612815565b17610e09565b90565b65ffffffffffff1690565b61289161288c6128969261034c565b61091b565b612872565b90565b6128ad6128a86128b292612872565b61091b565b61034c565b90565b90565b6128cc6128c76128d1926128b5565b61091b565b61034c565b90565b6128de60306128b8565b90565b64ffffffffff1690565b6128ff6128fa6129049261034c565b61091b565b6128e1565b90565b61291b612916612920926128e1565b61091b565b61034c565b90565b612982612995929361297b61296d61296861296261295461294f61298798612949610e25565b506124cd565b6124d9565b61295c610db5565b906110e7565b9361287d565b612899565b6129756128d4565b906110e7565b17936128eb565b612907565b61298f6127e6565b906110e7565b1790565b6001906129a461104c565b5060208151910120035f5260ff1960205f201690565b906129c361104c565b505f5260205260405f2090565b5f90565b6129e6906129e06129d0565b50610c94565b90565b5d565b906129f5611a43565b5081518060401b6bfe61000180600a3d393df3000161fffe8211840152600b8101601584015ff0928315612a265752565b63301164255f526004601cfd5b612a3b61104c565b505c90565b612a5f90612a59612a53612a649461034c565b916128e1565b90610dc2565b6128e1565b90565b612a6f610b45565b50612aa4612a9682612a90612a826110b2565b612a8a6127e6565b90611cc5565b906110e7565b612a9e6110b2565b90610dc6565b612abd612ab7612ab2610b65565b61034c565b9161034c565b145f14612b3957612b35612b2f612b2a612b25612b06612b00435b612afa612af5612af08a612aea6128d4565b90610dc6565b61287d565b612899565b90611cc5565b956128eb565b612b1f612b116127e6565b612b19612357565b90610a15565b90612a40565b612907565b61034c565b9161034c565b1190565b612b35612b2f612b2a612b25612b06612b0042612ad8565b612bb3612bb891612b60610e25565b50612bad6060612ba6612b94612b826005612b7c5f8801611af2565b906116f2565b612b8e60208701611af2565b90611708565b612ba060408601612272565b9061171e565b9201612272565b90611734565b611a66565b80612bd3612bcd612bc85f61093a565b6100fb565b916100fb565b14612bdc573b90565b612be46100e2565b6321f9f13f60e11b815280612bfb6004820161018a565b0390fd5b60105f604492602095829560145260345263a9059cbb60601b82525af13d1560015f5114171615612c30575f603452565b6390b8ec185f526004601cfd5b905f8092389238915af115612c4e57565b63b12d13eb5f526004601cfd5b60246010602093928493612c6d610e25565b506014526370a0823160601b5f525afa601f3d11166020510290565b929091612ca3612c9d858584908692613283565b156102d4565b612cae575b50505050565b612cbb93929091926132ca565b5f808080612ca8565b90612cce906109b4565b5f5260205260405f2090565b90612ce4906109b4565b5f5260205260405f2090565b90612cfa90610a3e565b5f5260205260405f2090565b90612d1090610a3e565b5f5260205260405f2090565b612d94612d9991612d2b61104c565b50612d8e612d6f612d5d612d4b6007612d455f8701610e72565b90612cc4565b612d5760208601610e72565b90612cda565b612d6960408501610e56565b90612cf0565b91612d886080612d8160608401610e56565b9201610e56565b906122c1565b90612d06565b610ce3565b90565b90612da7910261034c565b90565b5190565b60200190565b612dce612dc9612dc383612daa565b92612dae565b611f03565b9060208110612ddc575b5090565b612dee905f19906020036008026110e3565b165f612dd8565b90612dfe61104c565b50612e07610b45565b50612e65612e60612e4e612e3c612e2a6005612e245f8901610e72565b906116f2565b612e3660208801610e72565b90611708565b612e4860408701610e56565b9061171e565b612e5a60608601610e56565b90611734565b611a66565b80612e80612e7a612e755f61093a565b6100fb565b916100fb565b1461303457612efc612ef6612ef1612eec612e9a86613357565b94612eb8612eaa60808a01610e56565b612eb26115d5565b90612d9c565b612ee6612ed8612eca60808c01610e56565b612ed26115d5565b90612d9c565b612ee06115d5565b90610a15565b9161336e565b612db4565b6101b9565b916101b9565b0361301157612f12612f0d83610d6b565b612702565b91612f1c81612d1c565b612f3d612f37612f32612f2d610b65565b610e09565b6101b9565b916101b9565b14612f49575050905f90565b5f612fc791612fc184612fbc612f95612f83612f716007612f6b898901610e72565b90612cc4565b612f7d60208801610e72565b90612cda565b612f8f60408701610e56565b90612cf0565b612fb6612fa460608701610e56565b612fb060808801610e56565b90610a15565b90612d06565b6111c0565b01610e72565b8291612ff37fa8080584ebb92497a93bf0923d88f7a218d6b2b12e73938ec37157d8df9c561e926109b4565b92613008612fff6100e2565b92839283611f2c565b0390a290600190565b6130196100e2565b63162c5b6560e01b8152806130306004820161018a565b0390fd5b61303c6100e2565b6321f9f13f60e11b8152806130536004820161018a565b0390fd5b90565b61306e61306961307392613057565b61091b565b61034c565b90565b9161309c90939193613089858290610e29565b94906130968587906133e6565b91610e41565b906130a5610e25565b926130ae610e25565b9460015b156130e1575b6130d86130d25f966130cc60408801610e56565b90610a15565b96610e63565b949594956130b2565b856130f46130ee8361034c565b9161034c565b106130b85750613161919450613167936131529161312361311e6131195f8490610ca0565b610a08565b612a67565b613169575b509261314c6020613145600361313f5f8601610e72565b906109c0565b9201610e72565b906109d6565b9161315c83610a08565b610a15565b90610a5d565b565b906131ce613175611c53565b9161318a81613184600261305a565b906115f6565b6131c8816131c26131b38b6131ad60206131a660038c906109c0565b9201610e72565b906109d6565b916131bd83610a08565b610a15565b90610a5d565b90611cc5565b916131da5f8701610e72565b91909161322561321361320d7f3781e851432a339d869c35381daaa3d38116d4c213be17a65bd47ca16c450409936109b4565b936109b4565b9361321c6100e2565b91829182610541565b0390a35f613128565b916080939161323b61104c565b506040519384526020840152604083015260608201522090565b92909160a0949261326461104c565b5060405194855260208501526040840152606083015260808201522090565b601c5f6064928194602096989798613299610b45565b506040519960605260405260601b602c526323b872dd60601b600c525af13d1560015f51141716915f606052604052565b916040519260601b60601c6074840152836054840152603483015260601b6020820152631b63c28b60611b81526e22d473030f116ddee9f6b43ac78ba39060014614908115613346575b60845f9293836010389401915af1161561332b5750565b600490677939f4248757f0fd5f5260a01c151560021b601801fd5b5f91506084833b1515925050613314565b61335f61104c565b505f5260205f2090565b606090565b909291613379613369565b506040519380820361ffff16926001840182601f8801833c8386015160ff16156133b6575b5010810283525f816020850101526040830101604052565b9060018194923b03918260401c3d3d3e828403838511029003911102915f61339e565b6133e360206107be565b90565b9061340e613409613404613427946133fc610e25565b506001610cb6565b610ce3565b6127b3565b6134226134196133d9565b915f8301610cfd565b61342a565b90565b613432610e25565b505b6020812080825282805f030681101561344d5750613434565b9050069056fea2646970667358221220465da8eeb7695e18cd7a7179f1f70cb5226d5cb328ff6c1a4a1dcff3cd4fca4964736f6c63430008190033